Shiro笔记(四)----身份验证之Realm

来源:互联网 发布:我的老婆是警花知君txt 编辑:程序博客网 时间:2024/06/03 15:36

一、Realm简介


1.什么是Realm


Realm 是可以访问程序特定的安全数据如用户、角色、权限等的一个组件。Realm会将这些程序特定的安全数据转换成一种shiro可以理解的形式,shiro就可以依次提供容易理解的Subject程序API而不管有多少数据源或者程序中你的数据如何组织。

Realm 通常和数据源如数据库、LDAP目录、文件系统或者其它类似的数据源是一对一的关系,所以,可以用数据源相应的API如JDBC、File IO、 hibernate 或者JPA以及其它的API来实现Realm接口,从而获取授权的相关数据(角色、权限等)。

realm本质上就是一个指定安全的DAO。

因为大部分这类数据源通常都会同时存储认证数据(如密码)和授权数据(如角色和权限),所以每一个Shiro Realm都可以同时执行认证和授权操作。


总结: shiro要进行身份验证,就要从realm中获取相应的身份信息来进行验证,简单来说,我们可以自行定义realm,在realm中,从数据库获取身份信息,然后和 用户输入的身份信息进行匹配。这一切都由我们自己来定义。


2.为什么要用Realm


在前面的例子中,我们将身份信息(用户名/密码/角色/权限)写在配置文件中,但是实际开发中,这些身份信息应该保存在数据中,因此我们需要自定义Realm来从数据中获取身份信息,进行验证。


3.Realm 配置


如果使用Shiro的INI配置文件,你能够自定义及引用Realm,就像在[main]项中的任何其他对象一样,但它们在securityManager中采用两种方法之一进行配置:显式或隐式。


显式赋值:


这是一个显式的配置方法,在定义一个或多个Realm后,将它们作为securityManager对象的集合属性。

例如:

fooRealm = com.turing.foo.RealmbarRealm = com.turing.another.RealmbazRealm = com.turing.baz.RealmsecurityManager.realms = $fooRealm, $barRealm,$bazRealm

显式分配是确定的--你控制具体使用哪一个Realm及它们用于身份验证和授权的顺序,显示指定就是常见的方式,即定义Realm后再为securityManager按需要的顺序指定Realm。


隐式赋值:


如果因为某些原因(可能是定义的Realm太多?)不想为securityManager.realms指定,我们也可以使用隐式方式。

也就是说,把上面的配置改成如下形式就是隐式方式了:

fooRealm = com.company.foo.RealmbarRealm = com.company.another.RealmbazRealm = com.company.baz.Realm


隐式方式其实就是不指定,只定义(define),Shiro会搜索配置中所有的Realm并将它们一一指定给securityManager。

使用隐式方式时只要稍微改一下Realm的定义,Shiro就可能会给我们来个惊喜。


4.Realms的认证实现


Shiro的认证过程最终会交由Realm执行,这时会调用Realm的getAuthenticationInfo(token)方法。
  
  该方法通常会在org.apache.shiro.realm.AuthenticatingRealm中实现,当然,这个方法中会调用到具体realm实现的方法。


该方法主要执行以下操作:

1、检查提交的进行认证的令牌信息
2、根据令牌信息从数据源(通常为数据库)中获取用户信息
3、对用户信息进行匹配验证。
4、验证通过将返回一个封装了用户信息的AuthenticationInfo实例。
5、验证失败则抛出AuthenticationException异常信息。
 
这是对所有Realm getAuthenticationInfo 实现的最高级别的工作流,验证通过后,就返回一个非空的AuthenticationInfo 实例来代表来自于该数据源的Subject 帐户信息。



5.身份验证流程


               身份验证: 即在应用中谁能证明他就是他本人。一般提供如他们的身份ID一些标识信息来表明他就是他本人,如提供身份证,用户名/密码来证明。


5.1、基本概念


    Principals(身份):Subject 的 identifying attributes(标识属性)。比如我们登录提交的用户名。

    Credentials(凭证):用来作为一种起支持作用的证据,此证据包含身份证明。比如我们登录提供的密码。

5.2、认证的基本步骤

    收集Subjects 提交的Principals(身份)和Credentials(凭证);

    提交Principals(身份)和Credentials(凭证)进行身份验证;

    如果提交成功,则允许访问,否则重新进行身份验证或者阻止访问。

  AuthenticationToken:Shiro 中代表提交的 Principals(身份) 和 Credentials (凭证) 的身份验证系统的最基本接口。

  UsernamePasswordToken :AuthenticationToken 的接口的实现类,支持最常见的用户名/密码的身份验证
提交用户名/密码进行认证

Subject currentUser = SecurityUtils.getSubject();currentUser.login(token);

5.3、处理认证成功和失败

    认证成功:没有返回,也没有异常,通过。

    认证失败,拋出异常,可以在程序中捕获并处理


5.4、认证顺序





5.5、认证过程






Step 1:应用程序代码调用 Subject.login 方法,传递创建好的包含终端用户的 Principals(身份)和 Credentials(凭证)的 AuthenticationToken 实例

Step 2:Subject 实例,通常为 DelegatingSubject(或子类)委托应用程序的 SecurityManager 通过调用 securityManager.login(token) 开始真正的验证。

Step 3:SubjectManager 接收 token,调用内部的 Authenticator 实例调用 authenticator.authenticate(token)。 Authenticator 通常是一个 ModularRealmAuthenticator 实例,支持在身份验证中协调一个或多个Realm 实例。


Step 4:如果应用程序中配置了一个以上的 Realm,ModularRealmAuthenticator 实例将利用配置好的AuthenticationStrategy 来启动 Multi-Realm 认证尝试。在Realms 被身份验证调用之前,期间和以后,AuthenticationStrategy 被调用使其能够对每个Realm 的结果作出反应。

Step 5:每个配置的 Realm 用来帮助看它是否支持提交的AuthenticationToken。如果支持,那么支持 Realm 的 getAuthenticationInfo 方法将会伴随着提交的 token 被调用。getAuthenticationInfo 方法有效地代表一
个特定 Realm 的单一的身份验证尝试。



二、使用Realm


首先自定义一个MyRealm类,继承AuthorizingRealm,父类AuthorizingRealm将获取Subject相关信息分成两步:获取身份验证信息(doGetAuthenticationInfo)及授权信息(doGetAuthorizationInfo);


1、doGetAuthenticationInfo 获取身份验证相关信息:首先根据传入的用户名获取User信息;然后如果user为空,那么抛出没找到帐号异常UnknownAccountException;如果user找到但锁定了抛出锁定异常LockedAccountException;最后生成AuthenticationInfo信息,交给间接父类AuthenticatingRealm使用CredentialsMatcher进行判断密码是否匹配,如果不匹配将抛出密码错误异常IncorrectCredentialsException;另外如果密码重试此处太多将抛出超出重试次数异常ExcessiveAttemptsException;

2、doGetAuthorizationInfo 获取授权信息:PrincipalCollection是一个身份集合,因为我们现在就一个Realm,所以直接调用getPrimaryPrincipal得到之前传入的用户名即可;然后根据用户名调用UserService接口获取角色及权限信息。


2.1、支持单个Realm


自定义一个Realm继承AuthorizingRealm实现其中的doGetAuthenticationInfo和doGetAuthorizationInfo方法:

package com.fendo.temp;import java.util.HashSet;import java.util.Set;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.IncorrectCredentialsException;import org.apache.shiro.authc.SimpleAuthenticationInfo;import org.apache.shiro.authc.UnknownAccountException;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class MyRealm1 extends AuthorizingRealm {    private static final transient Logger log = LoggerFactory.getLogger(MyRealm1.class);    /**     * 获取身份信息,我们可以在这个方法中,从数据库获取该用户的权限和角色信息     */    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {        log.info("----------doGetAuthorizationInfo方法被调用----------");        String username = (String) getAvailablePrincipal(principals);        //我们可以通过用户名从数据库获取权限/角色信息        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();        //权限        Set<String> s = new HashSet<String>();        s.add("printer:print");        s.add("printer:query");        info.setStringPermissions(s);        //角色        Set<String> r = new HashSet<String>();        r.add("role1");        info.setRoles(r);        return info;    }    /**     * 在这个方法中,进行身份验证     */    @Override    protected AuthenticationInfo doGetAuthenticationInfo(            AuthenticationToken token) throws AuthenticationException {        //用户名        String username = (String) token.getPrincipal();        log.info("username:"+username);        //密码        String password = new String((char[])token.getCredentials());        log.info("password:"+password);        //从数据库获取用户名密码进行匹配,这里为了方面,省略数据库操作        if(!"admin".equals(username)){            throw new UnknownAccountException();        }        if(!"123".equals(password)){            throw new IncorrectCredentialsException();        }        //身份验证通过,返回一个身份信息        AuthenticationInfo aInfo = new SimpleAuthenticationInfo(username,password,getName());        return aInfo;    }}

然后新建一个测试类:

package com.fendo.temp;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.IncorrectCredentialsException;import org.apache.shiro.authc.LockedAccountException;import org.apache.shiro.authc.UnknownAccountException;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.config.IniSecurityManagerFactory;import org.apache.shiro.mgt.SecurityManager;import org.apache.shiro.subject.Subject;import org.apache.shiro.util.Factory;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class Main {private static final transient Logger log = LoggerFactory.getLogger(Main.class);public static void main(String[] args) {        //获取SecurityManager的实例        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-realm.ini");                        SecurityManager securityManager = factory.getInstance();        SecurityUtils.setSecurityManager(securityManager);        Subject currenUser = SecurityUtils.getSubject();        //如果还未认证        if(!currenUser.isAuthenticated()){            UsernamePasswordToken token = new UsernamePasswordToken("admin","123");            token.setRememberMe(true);            try {                currenUser.login(token);            } catch (UnknownAccountException uae) {                log.info("没有该用户: " + token.getPrincipal());            } catch (IncorrectCredentialsException ice) {                log.info( token.getPrincipal() + " 的密码不正确!");            } catch (LockedAccountException lae) {                log.info( token.getPrincipal() + " 被锁定 ,请联系管理员");            }catch (AuthenticationException ae) {                //其他未知的异常            }        }        if(currenUser.isAuthenticated())            log.info("用户 "+currenUser.getPrincipal() +" 登录成功");        //是否有role1这个角色        if(currenUser.hasRole("role1")){            log.info("有角色role1");        }else{            log.info("没有角色role1");        }        //是否有对打印机进行打印操作的权限        if(currenUser.isPermitted("printer:print")){            log.info("可以对打印机进行打印操作");        }else {            log.info("不可以对打印机进行打印操作");        }    }}

在配置文件中配置(shiro-realm.ini)

#声明一个realm  MyRealm1=com.fendo.temp.MyRealm1#指定securityManager的realms实现  securityManager.realms=$MyRealm1

doGetAuthorizationInfo会执行两次,分别是在currenUser.hasRole() 和currenUser.isPermitted 方法调用时调用 。


2.2、支持多个Realm


有时候不单单只有一个Realm而是由多个,Shiro支持多个Realm验证,新建一个MyRealm2


package com.fendo.temp;import java.util.HashSet;import java.util.Set;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.IncorrectCredentialsException;import org.apache.shiro.authc.SimpleAuthenticationInfo;import org.apache.shiro.authc.UnknownAccountException;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class MyRealm2 extends AuthorizingRealm{private static final transient Logger log = LoggerFactory.getLogger(Main.class);    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {        String username = (String) getAvailablePrincipal(principals);        //通过用户名从数据库获取权限字符串        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();        //权限        Set<String> s = new HashSet<String>();        s.add("printer:print");        s.add("printer:query");        info.setStringPermissions(s);        //角色        Set<String> r = new HashSet<String>();        r.add("role1");        info.setRoles(r);        return info;    }    @Override    protected AuthenticationInfo doGetAuthenticationInfo(            AuthenticationToken token) throws AuthenticationException {        log.info("MyRealm2开始认证。。。。。。");        //用户名        String username = (String) token.getPrincipal();        log.info("username:"+username);        //密码        String password = new String((char[])token.getCredentials());        log.info("password:"+password);        //从数据库获取用户名密码进行匹配,这里为了方面,省略数据库操作        if(!"admin".equals(username)){            throw new UnknownAccountException();        }        if(!"123".equals(password)){            throw new IncorrectCredentialsException();        }        //身份验证通过        AuthenticationInfo aInfo = new SimpleAuthenticationInfo(username,password,getName());        return aInfo;    }}

然后在ini文件中进行配置,Realm验证的顺序就是在ini文件中配置的顺序,如下:

#声明一个realm  MyRealm1=com.fendo.temp.MyRealm1MyRealm2=com.fendo.temp.MyRealm2#ָ配置验证器securityManager.realms=$MyRealm1#配置验证器authenticator = org.apache.shiro.authc.pam.ModularRealmAuthenticator#配置策略# AllSuccessfulStrategy 表示 MyRealm1和MyRealm2 认证都通过才算通过authcStrategy = org.apache.shiro.authc.pam.AllSuccessfulStrategy#将验证器和策略关联起来authenticator.authenticationStrategy = $authcStrategy#配置验证器所使用的Realmauthenticator.realms=$MyRealm2,$MyRealm1#把Authenticator设置给securityManagersecurityManager.authenticator = $authenticator########################################################################### 1. AtLeastOneSuccessfulStrategy :如果一个(或更多)Realm 验证成功,则整体的尝试被认# 为是成功的。如果没有一个验证成功,则整体尝试失败。# 2. FirstSuccessfulStrategy 只有第一个成功地验证的Realm 返回的信息将被使用。所有进一步# 的Realm 将被忽略。如果没有一个验证成功,则整体尝试失败# 3. AllSucessfulStrategy 为了整体的尝试成功,所有配置的Realm 必须验证成功。如果没有一# 个验证成功,则整体尝试失败。# ModularRealmAuthenticator 默认的是AtLeastOneSuccessfulStrategy###########################################################################

securityManager会按照realms指定的顺序进行身份认证,其中有两个地方要注意下就是,Authenticator和AuthenticationStrategy,Strategy的意思就是策略。Authenticator就是验证器。


Authenticator的职责是验证用户帐号,是Shiro API中身份验证核心的入口点: 


public AuthenticationInfo authenticate(AuthenticationToken authenticationToken)  throws AuthenticationException;   

如果验证成功,将返回AuthenticationInfo验证信息;此信息中包含了身份及凭证;如果验证失败将抛出相应的AuthenticationException实现。


SecurityManager接口继承了Authenticator,另外还有一个ModularRealmAuthenticator实现,其委托给多个Realm进行验证,验证规则通过AuthenticationStrategy接口指定,默认提供的实现:


FirstSuccessfulStrategy:只要有一个Realm验证成功即可,只返回第一个Realm身份验证成功的认证信息,其他的忽略;


AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可,和FirstSuccessfulStrategy不同,返回所有Realm身份验证成功的认证信息;


AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有Realm身份验证成功的认证信息,如果有一个失败就失败了。
 
ModularRealmAuthenticator默认使用AtLeastOneSuccessfulStrategy策略。



新建测试类mains:


package com.fendo.temp;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.IncorrectCredentialsException;import org.apache.shiro.authc.LockedAccountException;import org.apache.shiro.authc.UnknownAccountException;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.config.IniSecurityManagerFactory;import org.apache.shiro.mgt.SecurityManager;import org.apache.shiro.subject.PrincipalCollection;import org.apache.shiro.subject.Subject;import org.apache.shiro.util.Factory;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class Mains {private static final transient Logger log = LoggerFactory.getLogger(Main.class);    public static void main(String[] args) {        //获取SecurityManager的实例        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-mutil-realm.ini");        SecurityManager securityManager = factory.getInstance();        SecurityUtils.setSecurityManager(securityManager);        Subject currenUser = SecurityUtils.getSubject();        //如果还未认证        if(!currenUser.isAuthenticated()){            UsernamePasswordToken token = new UsernamePasswordToken("admin","123");            token.setRememberMe(true);            try {                currenUser.login(token);            } catch (UnknownAccountException uae) {                log.info("没有该用户: " + token.getPrincipal());            } catch (IncorrectCredentialsException ice) {                log.info( token.getPrincipal() + " 的密码不正确!");            } catch (LockedAccountException lae) {                log.info( token.getPrincipal() + " 被锁定 ,请联系管理员");            }catch (AuthenticationException ae) {                //其他未知的异常            }        }        if(currenUser.isAuthenticated())            log.info("用户 "+currenUser.getPrincipal() +" 登录成功");        //得到一个身份集合        PrincipalCollection principalCollection = currenUser.getPrincipals();    }}

输出如下:


2017-07-15 15:31:53,809 INFO [com.fendo.temp.Main] - MyRealm2开始认证。。。。。。 2017-07-15 15:31:53,809 INFO [com.fendo.temp.Main] - username:admin 2017-07-15 15:31:53,809 INFO [com.fendo.temp.Main] - password:123 2017-07-15 15:31:53,814 INFO [com.fendo.temp.MyRealm1] - MyRealm1开始认证。。。。。。 2017-07-15 15:31:53,814 INFO [com.fendo.temp.MyRealm1] - username:admin 2017-07-15 15:31:53,814 INFO [com.fendo.temp.MyRealm1] - password:123 

MyRealm1和MyRealm2依次执行。


2.3、自定义AuthenticationStrategy(验证策略)


我们也可以自定义AuthenticationStrategy,首先看其API:

//在所有Realm验证之前调用  AuthenticationInfo beforeAllAttempts(Collection<? extends Realm> realms, AuthenticationToken token) throws AuthenticationException; //在每个Realm之前调用  AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException;  //在每个Realm之后调用  AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo, Throwable t) throws AuthenticationException;  //在所有Realm之后调用  AuthenticationInfo afterAllAttempts(AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException;   

新建一个类继承AbstractAuthenticationStrategy:

package com.fendo.temp;import java.util.Collection;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.pam.AbstractAuthenticationStrategy;import org.apache.shiro.realm.Realm;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class MyAuthenticationStrategy extends AbstractAuthenticationStrategy{private static final transient Logger log = LoggerFactory.getLogger(MyAuthenticationStrategy.class);    /**     * 所有Realm验证之前调用     */    @Override    public AuthenticationInfo beforeAllAttempts(            Collection<? extends Realm> realms, AuthenticationToken token)            throws AuthenticationException {        log.info("===============beforeAllAttempts方法被调用==================");        return super.beforeAllAttempts(realms, token);    }    /**     * 每一个Realm验证之前调用     */    @Override    public AuthenticationInfo beforeAttempt(Realm realm,            AuthenticationToken token, AuthenticationInfo aggregate)            throws AuthenticationException {        log.info("===============beforeAttempt方法被调用==================");        return super.beforeAttempt(realm, token, aggregate);    }    /**     * 每一个Realm验证之后调用     */    @Override    public AuthenticationInfo afterAttempt(Realm realm,            AuthenticationToken token, AuthenticationInfo singleRealmInfo,            AuthenticationInfo aggregateInfo, Throwable t)            throws AuthenticationException {        log.info("===============afterAttempt方法被调用==================");        return super.afterAttempt(realm, token, singleRealmInfo, aggregateInfo, t);    }    /**     * 所有Realm验证之后调用     */    @Override    public AuthenticationInfo afterAllAttempts(AuthenticationToken token,            AuthenticationInfo aggregate) throws AuthenticationException {        log.info("===============afterAllAttempts方法被调用==================");        return super.afterAllAttempts(token, aggregate);    }}

要想让我们自定义的AbstractAuthenticationStrategy起作用,需在ini配置文件中将authcStrategy =org.apache.shiro.authc.pam.AllSuccessfulStrategy 
改为authcStrategy = com.shiro.authenticationstrategy.MyAuthenticationStrategy 即可,测试代码不变,然后运行mains,查看运行结果如下:

2017-07-15 15:42:37,464 INFO [com.fendo.temp.MyAuthenticationStrategy] - ===============beforeAllAttempts方法被调用================== 2017-07-15 15:42:37,466 TRACE [org.apache.shiro.authc.pam.ModularRealmAuthenticator] - Iterating through 2 realms for PAM authentication 2017-07-15 15:42:37,466 INFO [com.fendo.temp.MyAuthenticationStrategy] - ===============beforeAttempt方法被调用================== 2017-07-15 15:42:37,466 TRACE [org.apache.shiro.authc.pam.ModularRealmAuthenticator] - Attempting to authenticate token [org.apache.shiro.authc.UsernamePasswordToken - admin, rememberMe=true] using realm [com.fendo.temp.MyRealm2@17d99928] 2017-07-15 15:42:37,466 INFO [com.fendo.temp.Main] - MyRealm2开始认证。。。。。。 2017-07-15 15:42:37,466 INFO [com.fendo.temp.Main] - username:admin 2017-07-15 15:42:37,466 INFO [com.fendo.temp.Main] - password:123 2017-07-15 15:42:37,469 DEBUG [org.apache.shiro.realm.AuthenticatingRealm] - Looked up AuthenticationInfo [admin] from doGetAuthenticationInfo 2017-07-15 15:42:37,469 DEBUG [org.apache.shiro.realm.AuthenticatingRealm] - AuthenticationInfo caching is disabled for info [admin].  Submitted token: [org.apache.shiro.authc.UsernamePasswordToken - admin, rememberMe=true]. 2017-07-15 15:42:37,469 DEBUG [org.apache.shiro.authc.credential.SimpleCredentialsMatcher] - Performing credentials equality check for tokenCredentials of type [[C and accountCredentials of type [java.lang.String] 2017-07-15 15:42:37,469 DEBUG [org.apache.shiro.authc.credential.SimpleCredentialsMatcher] - Both credentials arguments can be easily converted to byte arrays.  Performing array equals comparison 2017-07-15 15:42:37,470 INFO [com.fendo.temp.MyAuthenticationStrategy] - ===============afterAttempt方法被调用================== 2017-07-15 15:42:37,470 INFO [com.fendo.temp.MyAuthenticationStrategy] - ===============beforeAttempt方法被调用================== 2017-07-15 15:42:37,471 TRACE [org.apache.shiro.authc.pam.ModularRealmAuthenticator] - Attempting to authenticate token [org.apache.shiro.authc.UsernamePasswordToken - admin, rememberMe=true] using realm [com.fendo.temp.MyRealm1@2fc14f68] 2017-07-15 15:42:37,471 INFO [com.fendo.temp.MyRealm1] - MyRealm1开始认证。。。。。。 2017-07-15 15:42:37,471 INFO [com.fendo.temp.MyRealm1] - username:admin 2017-07-15 15:42:37,471 INFO [com.fendo.temp.MyRealm1] - password:123 2017-07-15 15:42:37,471 DEBUG [org.apache.shiro.realm.AuthenticatingRealm] - Looked up AuthenticationInfo [admin] from doGetAuthenticationInfo 2017-07-15 15:42:37,471 DEBUG [org.apache.shiro.realm.AuthenticatingRealm] - AuthenticationInfo caching is disabled for info [admin].  Submitted token: [org.apache.shiro.authc.UsernamePasswordToken - admin, rememberMe=true]. 2017-07-15 15:42:37,471 DEBUG [org.apache.shiro.authc.credential.SimpleCredentialsMatcher] - Performing credentials equality check for tokenCredentials of type [[C and accountCredentials of type [java.lang.String] 2017-07-15 15:42:37,471 DEBUG [org.apache.shiro.authc.credential.SimpleCredentialsMatcher] - Both credentials arguments can be easily converted to byte arrays.  Performing array equals comparison 2017-07-15 15:42:37,471 INFO [com.fendo.temp.MyAuthenticationStrategy] - ===============afterAttempt方法被调用================== 2017-07-15 15:42:37,472 INFO [com.fendo.temp.MyAuthenticationStrategy] - ===============afterAllAttempts方法被调用================== 2017-07-15 15:42:38,043 INFO [com.fendo.temp.Main] - 用户 admin 登录成功 

可以从上面的输出中,清楚的看到我们自定义的策略中,各个方法被调用的顺序。


原创粉丝点击