shiro的实现权限管理的流程
一、登录认证
-
发起请求之后:会经过doFilter判断需要哪些权限,在复习shiro之前需要对springMvc有一定了解 ,根据debug顺便复习一下MVC的处理流程—根据递归调用栈:
-
首先根据Httpservlet判断是post还是Get请求
-
根据servlet中的request携带的的路径以及参数信息交给前端控制器处理分发
-
DispatcherServlet前端控制器将请求信息转发给RequestMappingHandlerAdapter映射处理器进程处理转发
-
ModelAndView mav;
mav = invokeHandlerMethod(request, response, handlerMethod);处理得到一个ModelAndView 视图模型
-
进一步通过method.invoke方法,反射的机制还有动态代理的机制进行回调Controller方法(回调是满足方法的条件之后重新执行)
-
-
回到shrio部分:
-
权限验证部分
-
controller层:subject主体实例调用login方法
Subject subject = SecurityUtils.getSubject(); try { subject.login(token);//核心 return R.ok();
-
实际调用:public class DelegatingSubject implements Subject
public void login(AuthenticationToken token) throws AuthenticationException { clearRunAsIdentitiesInternal(); Subject subject = securityManager.login(this, token);//调用
-
实际调用:securityManager
public void login(AuthenticationToken token) throws AuthenticationException { clearRunAsIdentitiesInternal(); Subject subject = securityManager.login(this, token)//实际实例的方法调用
-
实际调用:AuthenticationInfo
public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException { AuthenticationInfo info;//实际 try { info = authenticate(token);//进一步调用
-
然而:AuthenticationInfo方法被我们重写了里面的逻辑,实际查询数据库验证账户逻辑需要我们自己编写:UserRealm extends AuthorizingRealm
```java @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = (String) token.getPrincipal(); Map<String, Object> map = new HashMap<>(16); map.put("username", username); String password = new String((char[]) token.getCredentials()); UserDao userMapper = ApplicationContextRegister.getBean(UserDao.class); // 查询用户信息 UserDO user = userMapper.list(map).get(0); ```
二、授权部分
-
点击之后同样是先是 springMVC处理转发
-
关于shiro授权的部分
- 显示mvc根据请求映射处理器转发到后端的controller层
@RequiresPermissions("sys:role:role") @GetMapping("/list") @ResponseBody() List<RoleDO> list() { List<RoleDO> roles = roleService.list(); return roles; }
-
cglib动态代理的方式基于aop?
package org.apache.shiro.authz.aop; import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.authz.annotation.Logical; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresRoles; import org.apache.shiro.subject.Subject; import java.lang.annotation.Annotation; /** * Checks to see if a @{@link org.apache.shiro.authz.annotation.RequiresPermissions RequiresPermissions} annotation is * declared, and if so, performs a permission check to see if the calling <code>Subject</code> is allowed continued * access. * * @since 0.9.0 */ public class PermissionAnnotationHandler extends AuthorizingAnnotationHandler { /** * Default no-argument constructor that ensures this handler looks for * {@link org.apache.shiro.authz.annotation.RequiresPermissions RequiresPermissions} annotations. */ public PermissionAnnotationHandler() { super(RequiresPermissions.class);//注解的类作为构造函数参数 ----核心 }
-
动态代理调用:interface org.apache.shiro.authz.annotation.RequiresRoles
@Override @Nullable public Object proceed() throws Throwable { // We start with an index of -1 and increment early. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // Evaluate dynamic method matcher here: static part will already have // been evaluated and found to match. InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { // Dynamic matching failed. // Skip this interceptor and invoke the next in the chain. return proceed(); } } else { // It's an interceptor, so we just invoke it: The pointcut will have // been evaluated statically before this object was constructed. return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); //调用interface org.apache.shiro.authz.annotation.RequiresRoles--核心 } }
-
调用目标方法
public Object invoke(MethodInvocation methodInvocation) throws Throwable { org.apache.shiro.aop.MethodInvocation mi = createMethodInvocation(methodInvocation); return super.invoke(mi);//目标方法 }
-
进一步调用:DegatingSubject中的方法:
public void checkPermission(String permission) throws AuthorizationException { assertAuthzCheckPossible(); securityManager.checkPermission(getPrincipals(), permission);//权限验证部分 }
-
继续调用:抽象类AuthorizingRealm类中的获取授权信息方法
public abstract class AuthorizingRealm extends AuthenticatingRealm
if (info == null) { // Call template method if the info was not found in a cache info = doGetAuthorizationInfo(principals);//获取授权信息 // If the info is not null and the cache has been created, then cache the authorization info. if (info != null && cache != null) { if (log.isTraceEnabled()) { log.trace("Caching authorization info for principals: [" + principals + "]."); } Object key = getAuthorizationCacheKey(principals); cache.put(key, info); } }
-
然后到自己继承抽象类重写的方法中:自定义查询数据库的逻辑:根据三表关联查询jion on查找:
@Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) { Long userId = ShiroUtils.getUserId(); MenuService menuService = ApplicationContextRegister.getBean(MenuService.class); Set<String> perms = menuService.listPerms(userId);//获取权限信息 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.setStringPermissions(perms); return info; }
-
ModlarRealmAuthorizer类中的方法调用判断是否具有访问权限
public boolean isPermitted(PrincipalCollection principals, String permission) { assertRealmsConfigured(); for (Realm realm : getRealms()) { if (!(realm instanceof Authorizer)) continue; if (((Authorizer) realm).isPermitted(principals, permission)) { return true; } } return false; }
-
判断完成递归栈在弹栈
public void checkPermission(PrincipalCollection principals, String permission) throws AuthorizationException { assertRealmsConfigured(); if (!isPermitted(principals, permission)) { //权限判断完成弹栈 throw new UnauthorizedException("Subject does not have permission [" + permission + "]"); } }
-
-
补充授权过程:
3. 动态代理调用:interface org.apache.shiro.authz.annotation.RequiresRoles
4. 调用目标方法
8. ModlarRealmAuthorizer类中的方法调用判断是否具有访问权限