Apache Shiro验证: 已记住(Remembered) vs 已验证(Authenticated)

 
Apache Shiro验证(Authentication)

验证(Authentication):身份验证的过程--也就是证明一个用户的真实身份。为了证明用户身份,需要提供系统理解和相信的身份信息和证据。
需要通过向shiro提供用户的身份(Principals)和证明(credentials)来判定是否和系统所要求的匹配。

身份(Principals)是Subject的“身份属性”,可以是任何与Subject相关的标识,比如说名称(给定名称)、名字(姓或者昵称)、用户名、安全号码等等,当然像昵称这样的内容不能很好的对Subject进行独特标识,所以最好的身份信息(Principals)是使用在程序中唯一的标识--典型的使用用户名或邮件地址。

最主要的身份
虽然shiro可以使用任何数量的身份,Shiro还是希望一个程序精确地使用一个主要的身份--一个仅有的唯一标识Subject值。在多数程序中经常会是一个用户名、邮件地址或者全局唯一的用户ID。

证明(Credentials)通常是只有Subject知道的机密内容,用来证明他们真正拥有所需的身份,一些简单的证书例子如密码、指纹、眼底扫描和X.509证书等。

最常见的身份/证明是用户名和密码,用户名是所需的身份说明,密码是证明身份的证据。如果一个提交的密码和系统要求的一致,程序就认为该用户身份正确,因为其他人不应该知道同样的密码。

Authenticating对象
Subject验证的过程可以有效地划分分以下三个步骤:
1.收集Subject提交的身份和证明;
2.向Authenticating提交身份和证明;
3.如果提交的内容正确,允许访问,否则重新尝试验证或阻止访问。

下面的代码示范了Shiro API如何实现这些步骤:
第一步:收集用户身份和证明
//Example using mostcommon scenario of username/password pair:
UsernamePasswordTokentoken = new UsernamePasswordToken(username, password);

//”Remember Me” built-in:
token.setRememberMe(true);

在这里我们使用UsernamePasswordToken,支持所有常用的用户名/密码验证途径,这是一个org.apache.shiro.authc.AuthenticationToken接口的实现,这个接口被shiro认证系统用来提交身份和证明。

注意shiro并不关心你如何获取这些住处:也许是用户从一个HTML表单中提交的,或者可能从一个HTTP请求字串中解析的,也可能来自于Swing或者Flex GUI的密码表单,或者通过命令行参数得到。从程序终端用户获取信息的过程与shiro的AuthenticationToken完全无关。
你可以随自己喜欢构造和引用AuthenticationToken--它是协议不可知论者。

这个例子同样显示我们希望shiro在尝试验证时执行“Remember Me”服务,这确保shiro在用户今后返回系统时能记住他们的身份,我们会在以后的章节讨论“Remember Me”服务。

第二步:提交身份和证明
当身份和证明住处被收集并实例化为一个认证令牌后,我们需要向shiro提交令牌以执行真正的验证尝试:
Subject currentUser =SecurityUtils.getSubject();

currentUser.login(token);

在获取当前执行的Subject后,我们执行一个单独的login命令,将之前创建的认证令牌实例传给它。

使用login方法将有效地执行身份验证。

第三步:处理成功或失败
当login函数没有返回信息时表明验证通过了。程序可以继续运行,此时执行SecurityUtils.getSubject()将返回验证后的Subject实例,subject.isAuthenticated()将返回true。

但是如果login失败了呢?例如,用户提供了一个错误的密码或者因访问系统次数过多而被锁定将会怎样呢?

shiro拥有丰富的运行期异常(AuthenticationException)可以精确标明为何验证失败,你可以将login放入到try/catch块中并捕获所有你想捕获的异常并对它们做出处理。例如:
try {
currentUser.login(token);
} catch (UnknownAccountException uae ) { ...
} catch (IncorrectCredentialsException ice ) { ...
} catch (LockedAccountException lae ) { ...
} catch (ExcessiveAttemptsException eae ) { ...
} ... catch your own...
} catch (AuthenticationException ae ) {
//unexpected error?
}

//No problems,continue on as expected...

如果原有的异常不能满足你的需求,可以创建自定义的AuthenticationExceptions来表示特定的失败场景。

登录失败小贴士
虽然你的代码可以对指定的异常做出处理并执行某些所需的逻辑,但有经验的安全做法是仅向终端用户输出一般的失败信息,例如“错误的用户名和密码”。这确保不向尝试攻击你的黑客提供有用的信息。

已记住(Remembered) vs 已验证(Authenticated)
如上例所示,shiro支持在登录过程中执行"remember me",在此值得指出,一个已记住的Subject(remembered Subject)和一个正常通过认证的Subject(authenticated Subject)在shiro是完全不同的。

记住的(Remembered):一个被记住的Subject没有已知身份(也就是说subject.getPrincipals()返回空),但是它的身份被先前的认证过程记住,并存于先前session中,一个被认为记住的对象在执行subject.isRemembered()返回真。


已验证(Authenticated):一个被验证的Subject是成功验证后(如登录成功)并存于当前session中,一个被认为验证过的对象调用subject.isAuthenticated()将返回真。


以下参考 :http://blog.csdn.net/sinat_35767703/article/details/67633186

认证就是验证用户身份的过程。在认证过程中,用户需要提交实体信息(Principals)和凭据信息(Credentials)以检验用户是否合法。最常见的“实体/凭证”组合便是“用户名/密码”组合。

一、认证过程

1、收集实体/凭据信息

 

[java]  view plain  copy
  1. UsernamePasswordToken token =   new UsernamePasswordToken(username, password);  
  2.  token.setRememberMe(true);  

     UsernamePasswordToken支持最常见的用户名/密码的认证机制。同时,由于它实现了RememberMeAuthenticationToken接口,我们可以通过令牌设置“

 

 

记住我”的功能。 但是,已记住”和“已认证”是有区别的:   已记住的用户仅仅是非匿名用户,你可以通过subject.getPrincipals()获取用户信息。但是它并非是认证通过的用户,当你访问需要认证用户的功能时,你仍然需要重新提交认证信息。   这一区别可以参考淘宝网站,网站会默认记住登录的用户,再次访问网站时,对于非敏感的页面功能,页面上会显示记住的用户信息,但是当你访问网站账户信息时仍然需要再次进行登录认证。

2、提交实体/凭据信息

 

[java]  view plain  copy
  1. Subject currentUser = SecurityUtils.getSubject();     
  2. currentUser.login(token);  

     收集了实体/凭据信息之后,我们可以通过SecurityUtils工具类,获取当前的用户,然后通过调用login方法提交认证。

 

3、认证  

如果我们自定义Realm实现,比如我后面的例子中,自定义了ShiroDbRealm类,当执行currentUser.login(token)时,会先执行ShiroDbRealm.doGetAuthorizationInfo()进行认证

 

[java]  view plain  copy
  1. /**       * 验证当前登录的Subject        
  2. * @see经测试:本例中该方法的调用时机为   
  3. * LoginController.login()方法中执行Subject.login()时       
  4. */   
  5.    protected AuthenticationInfo   doGetAuthenticationInfo(AuthenticationTokenauthcToken)  throws AuthenticationException {  
  6.     //获取基于用户名和密码的令牌   
  7.     //实际上这个authcToken是从LoginController里面 currentUser.login(token)传过来的  
  8.     UsernamePasswordToken token =  (UsernamePasswordToken) authcToken;  
  9.     //从数据库中查询用户用信息  
  10.     Useruser = userService.getByAccount(token.getUsername());  
  11.    if(user != null) {  
  12.     //此处无需比对,比对的逻辑Shiro会做,  
  13.    //我们只需返回一个和令牌相关的正确的验证信息  
  14.      returnnew SimpleAuthenticationInfo(  user.getAccount(),  
  15.                                   user.getPassword(),getName());  
  16.     }else {  
  17.     //没有返回登录用户名对应的SimpleAuthenticationInfo对象时,  
  18.     // 就会在LoginController中抛出UnknownAccountException异常  
  19.        return null;   
  20.    }  
  21. }  

 4、认证处理

 

 

[java]  view plain  copy
  1. try {  
  2.          currentUser.login(token);  
  3. catch ( UnknownAccountException uae ) {  
  4.       ...  
  5. catch ( IncorrectCredentialsException ice ) {   
  6.       ...     
  7. catch ( LockedAccountException lae ) {  
  8.       ...     
  9. catch ( ExcessiveAttemptsException eae ) {  
  10.      ...    } ... catch your own ...       
  11. catch ( AuthenticationException ae) {  
  12.         //unexpected error?     }   

    如果login方法执行完毕且没有抛出任何异常信息,那么便认为用户认证通过。之后在应用程序任意地方调用SecurityUtils.getSubject()都可以获取到当前认证通过的用户实例,使用subject.isAuthenticated()判断用户是否已验证都将返回true.   相反,如果login方法执行过程中抛出异常,那么将认为认证失败。Shiro有着丰富的层次鲜明的异常类来描述认证失败的原因,如代码示例。

 

     二、登出操作

   登出操作可以通过调用subject.logout()来删除你的登录信息,如:

   currentUser.logout(); 

  //removes all identifying information

  //and invalidates their session too.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值