shiro的用户校验与授权处理流程调用栈2(详细)

shiro的实现权限管理的流程

一、登录认证

  1. 发起请求之后:会经过doFilter判断需要哪些权限,在复习shiro之前需要对springMvc有一定了解 ,根据debug顺便复习一下MVC的处理流程—根据递归调用栈:

    • 首先根据Httpservlet判断是post还是Get请求

    • 根据servlet中的request携带的的路径以及参数信息交给前端控制器处理分发

    • DispatcherServlet前端控制器将请求信息转发给RequestMappingHandlerAdapter映射处理器进程处理转发

    • ModelAndView mav;

      mav = invokeHandlerMethod(request, response, handlerMethod);处理得到一个ModelAndView 视图模型

    • 进一步通过method.invoke方法,反射的机制还有动态代理的机制进行回调Controller方法(回调是满足方法的条件之后重新执行)

  2. 回到shrio部分:

    • 权限验证部分

      1. controller层:subject主体实例调用login方法

                Subject subject = SecurityUtils.getSubject();
                try {
                    subject.login(token);//核心
                    return R.ok();
        
      2. 实际调用:public class DelegatingSubject implements Subject

            public void login(AuthenticationToken token) throws AuthenticationException {
                clearRunAsIdentitiesInternal();
                Subject subject = securityManager.login(this, token);//调用
        
      3. 实际调用:securityManager

            public void login(AuthenticationToken token) throws AuthenticationException {
                clearRunAsIdentitiesInternal();
                Subject subject = securityManager.login(this, token)//实际实例的方法调用
        
      4. 实际调用:AuthenticationInfo

            public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {
                AuthenticationInfo info;//实际
                try {
                    info = authenticate(token);//进一步调用
        
      5. 然而: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);
        
                ```
        

      二、授权部分

      1. 点击之后同样是先是 springMVC处理转发

      2. 关于shiro授权的部分

        1. 显示mvc根据请求映射处理器转发到后端的controller层
        	@RequiresPermissions("sys:role:role")
        	@GetMapping("/list")
        	@ResponseBody()
        	List<RoleDO> list() {
        		List<RoleDO> roles = roleService.list();
        		return roles;
        	}
        
        1. 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);//注解的类作为构造函数参数 ----核心
              }
          
        2. 动态代理调用: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--核心
          		}
          	}
          
          
        3. 调用目标方法

             public Object invoke(MethodInvocation methodInvocation) throws Throwable {
                  org.apache.shiro.aop.MethodInvocation mi = createMethodInvocation(methodInvocation);
                  return super.invoke(mi);//目标方法
              }
          
        4. 进一步调用:DegatingSubject中的方法:

              public void checkPermission(String permission) throws AuthorizationException {
                  assertAuthzCheckPossible();
                  securityManager.checkPermission(getPrincipals(), permission);//权限验证部分
              }
          
        5. 继续调用:抽象类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);
                      }
                  }
          
        6. 然后到自己继承抽象类重写的方法中:自定义查询数据库的逻辑:根据三表关联查询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;
          	}
          
          
        7. 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;
              }
          
          
        8. 判断完成递归栈在弹栈

              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类中的方法调用判断是否具有访问权限

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值