(4)shiro的执行流程

来源:互联网 发布:怎么成为一个程序员 编辑:程序博客网 时间:2024/05/21 03:54

当所有的配置都结束了,启动项目运行时,那么用户验证和权限验证又是怎么样的呢?

1.在LoginController中,一般的业务流程是这样的,在登录验证方法login(User user)中

首先通过SecurityManager获取主体Subject。

然后创建包含用户用户名和密码的token。 new一个UsernamePasswordToken(用户名,密码.toCharArray())。

核心方法 subject.login(token);

一。接着,开始刨底层源码了啊!!!!!

1.subject.login(token)

2.进入了实现类DelegatingSubject类中的login(token),在login方法中 有这样的操作this.securityManager.login(this, token); 即调用了SecurityManager的login方法 。

3.现在进入SecurityManager的login()方法中,即进入了他的实现类DefaultSecurityManager的login()方法中,在login(Subject subject, AuthenticationToken token)方法中,有这样的代码:

 AuthenticationInfo info;        try {            info = this.authenticate(token);            .......

即调用了authenticate(token)方法 ,返回了一个AuthenticationInfo 对象。

4.在authenticate(token)继续下钻,发现是AuthenticatingSecurityManager这个抽象类的 authenticate(AuthenticationToken token)方法 在这个方法中是这样的

 return this.authenticator.authenticate(token);

5.Authenticator是我们的身份校验的核心器。authenticator调用了authenticate方法 ,参数token是用户输入的身份和凭证。

6. 然后进入到了AbstractAuthenticator类的authenticate(AuthenticationToken token)方法,调用了 :info = this.doAuthenticate(token); 我的天哪 还要往下掉

7.进入到了 ModularRealmAuthenticator类的doAuthenticate(AuthenticationToken authenticationToken)方法中 首先先判断Realm的数量 ,如果是一个的话 就调用:

  return realms.size() == 1?this.doSingleRealmAuthentication((Realm)realms.iterator().next(), authenticationToken):this.doMultiRealmAuthentication(realms, authenticationToken);

8.doSingleRealmAuthentication方法 进入了 AuthenticationInfo info = realm.getAuthenticationInfo(token); 这个方法 继续…….

9.到了.AuthenticatingRealm info = this.doGetAuthenticationInfo(token); 一看这是个Realm 一看这个方法 不就是咱们自己实现的Realm继承了AuthorizingRealm 的那两个方法嘛 没错 最后走到了我们自己实现的Realm中。 大功告成!!!!

二。然后 ,精彩继续————————

在我自定义的Realm的doGetAuthenticationInfo中,代码是这样的:

        UsernamePasswordToken upToken = (UsernamePasswordToken) token;        String username = upToken.getUsername();        //查询真实的用户        User user = userService.findUserByUserName(username);        AuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),getName());

没错前面的都是为这一步做铺垫,业务逻辑我们先不要看,就看最后这一行 AuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),getName()) 将正确的用户的信息封装成了AuthenticationInfo 对象,并返回 。现在我们有了用户输入的token和此用户正确的账号密码。在哪里比较呢?我当时也纠结了很久。再找找看

在AuthenticatingRealm 类中 有这样的 构造方法

public AuthenticatingRealm() {        this((CacheManager)null, new SimpleCredentialsMatcher());    }

AuthenticatingRealm 在创建的时候就已经注入了SimpleCredentialsMatcher凭证匹配器 ,而我们的自定义的凭证匹配器继承了SimpleCredentialsMatcher ,所以在验证之前我们可以加入自己的业务,比如我加入了用户token密码的加盐HashMD5。

验证到此完结——————————–

三。权限

提示:下面的是抄的 权限我就只会用标签哪一种

流程如下:

1、首先调用Subject.isPermitted*/hasRole*接口,其会委托给SecurityManager,而SecurityManager接着会委托给Authorizer;

2、Authorizer是真正的授权者,如果我们调用如isPermitted(“user:view”),其首先会通过PermissionResolver把字符串转换成相应的Permission实例;

3、在进行授权之前,其会调用相应的Realm获取Subject相应的角色/权限用于匹配传入的角色/权限;

4、Authorizer会判断Realm的角色/权限是否和传入的匹配,如果有多个Realm,会委托给ModularRealmAuthorizer进行循环判断,如果匹配如isPermitted*/hasRole*会返回true,否则返回false表示授权失败。

ModularRealmAuthorizer进行多Realm匹配流程:

1、首先检查相应的Realm是否实现了实现了Authorizer;

2、如果实现了Authorizer,那么接着调用其相应的isPermitted*/hasRole*接口进行匹配;

3、如果有一个Realm匹配那么将返回true,否则返回false。

如果Realm进行授权的话,应该继承AuthorizingRealm,其流程是:

1.1、如果调用hasRole*,则直接获取AuthorizationInfo.getRoles()与传入的角色比较即可;

1.2、首先如果调用如isPermitted(“user:view”),首先通过PermissionResolver将权限字符串转换成相应的Permission实例,默认使用WildcardPermissionResolver,即转换为通配符的WildcardPermission;

2、通过AuthorizationInfo.getObjectPermissions()得到Permission实例集合;通过AuthorizationInfo. getStringPermissions()得到字符串集合并通过PermissionResolver解析为Permission实例;然后获取用户的角色,并通过RolePermissionResolver解析角色对应的权限集合(默认没有实现,可以自己提供);

3、接着调用Permission. implies(Permission p)逐个与传入的权限比较,如果有匹配的则返回true,否则false。