shiro开发文档阅读(一)认证

一 ,Authentication(身份验证)

在这里插入图片描述

1.shiro的身份认证

Authentication 是指身份验证的过程——即证明一个用户实际上是不是他们所说的他们是谁。对于一个用户证明自己 的身份来说,他们需要提供一些身份识别信息,以及某些你的系统能够理解和信任的身份证明。 这是通过提交用户的身份和凭证给 Shiro,以判断它们是否和应用程序预期的相匹配。

2.三个要素

subject

subject相当于 “ 用户 ”,就是当前与应用程序交互的用户

    //获取subject
    Subject subject = SecurityUtils.getSubject();

Principals

principals是subject的标识属性,可以理解为身份信息,可以是任何能够证明 Subject 的东西,如名,姓氏,用户名,社会保险号(相当于我们的身份证号码)等等,虽然 Shiro 可以代表任意数量的 Principals(身份),但 Shiro 期望应用程序有一个确切的‘主要 的’Principals(身份)——一个单一的值在应用程序内部唯一标识 Subject。这通常是一个用户名,电子邮件地址 或者在大多数应用中的全球唯一用户 ID

    //获取principals
    subject.getPrincipal();

Credentials

Credentials(凭证)通常是只被 Subject 知道的秘密值,它用来作为一种起支持作用的证据

subject认证过程

验证 Subjects 的过程中,可以有效地分解成三个不同的步骤:

  1. 收集 Subjects 提交的 Principals(身份)和 Credentials(凭证);
  2. 提交 Principals(身份)和 Credentials(凭证)进行身份验证;
  3. 如果提交成功,则允许访问,否则重新进行身份验证或者阻止访问

shiro提供非常丰富的运行时 AuthenticationException 层次结构,可以指出尝试失败的确切原因。你可以用一个 try/catch 块将 login 方法包围起来,然后捕捉任何你期望的异常并进行相应的反应

    try { 
    	currentUser.login(token); 
     } catch ( UnknownAccountException uae ) {} 
       catch ( IncorrectCredentialsException ice ) {}
       catch (LockedAccountException lae ) {}
       catch (ExcessiveAttemptsException eae ) {} 
       catch your own … } 
       catch ( AuthenticationException ae ) {         //unexpected error? } 

shiro官方推荐
虽然你的代码可以以特定的异常作出反应,并执行必要的逻 辑,最安全的做法是只显示通用的失败消息给终端用户,例如, “错误的用户名或密码。”。这样将确保具体的信息提供给黑 客可能试图攻击的媒介

详细分析下认证过程
1.收集 Subject 的 Principals(身份)和 Credentials(凭证)

先看一段源码

		//Shiro的org.apache.shiro.authc.AuthenticationToken的接口,是Shiro代表提交的Principals(身份)和Credentials(凭 证)的身份验证系统所使用的基本接口
    public interface AuthenticationToken extends Serializable {
                Object getPrincipal();
            
                Object getCredentials();
            }

他有两个实现类
RememberMeAuthenticationToken和HostAuthenticationToken
而我们常用的UsernamePasswordToken则实现了这两个接口,通过构造方法封装了用户名和密码,记住我服务默认是关闭的,需要手动开启


    public class UsernamePasswordToken implements HostAuthenticationToken, RememberMeAuthenticationToken {
       private String username;
       private char[] password;
       private boolean rememberMe;
       private String host;
   
       public UsernamePasswordToken() {
           this.rememberMe = false;
       }
   
       public UsernamePasswordToken(String username, char[] password) {
           this(username, (char[])password, false, (String)null);
       }
   
       public UsernamePasswordToken(String username, String password) {
           this(username, (char[])(password != null ? password.toCharArray() : null), false, (String)null);
       }

Shiro不关心你是如何获取此信息的:也许获得的数据是由用户提交的一个 HTML表单, 或者是从 HTTP 头中捕获,或者它是从一个 Swing 或 Flex GUI 密码表单,或者通过命令行参数。从终端用户收 集信息的过程与 Shiro 的 Authentication Token 概念是不挂钩的。

2.提交 Subject 的 Principals(身份)和 Credentials(凭证)

在 Principals(身份)和 Credentials(凭证)被收集以及被实例化为 AuthenticationToken 实例后,我们需要提交这个 token 给 Shiro 来执行真正的身份验证尝试:

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

在捕获到当前执行的 Subject 后,我们获得一个单一的 login 方法调用,并将之前获得的 AuthenticationToken 实例传递给它。 通过调用 login 方法,有效地体现了身份验证尝试。

3.处理登录

如果 login 方法返回平静地,就是它——我们所做的一切!该 Subject 已通过验证。应用程序线程可以不受干 扰地继续下去,而且所有进一步对 SecurityUtils.getSubject()的调用将返回认证后的 Subject 实例,同时任何对 subject.isAuthenticated()的调用将返回 true。

Remembered vs. Authenticated(记住我对比认证)
shiro对记住我subject和认证subject做了精确的区分
关系 — 互斥关系
RememberedMe:一个记住我的subject不是匿名的,是有确定身份的,也就是说,

    subject.getPrincipals()`返回是非空的
    subject.isRemembered()返回 true

但是,这个身份是之前session中被认证的

Authenticated(已认证):一个已认证的 Subject 是指在当前 Session 中被成功地验证过了(也就是说,login 方法被调用并且没有抛出异常)。如果 subject.isAuthenticated()返回 true 则认为 Subject 已通过验证。

为何有这样的区别?
“身份验证”这个词有很强的证明的意思在里面。也就是说,有一个预期保证 Subject 已经证明他们是他们所 说的谁。 当用户只记得之前与应用的交互时,认证将不复存在:被记住的身份 ID 使系统明白这个用户可能是谁,但在 现实中没有办法绝对保证被记住的 Subject 代表期望的用户。一旦 Subject 通过验证,它们将不再仅仅被认为 是被记住的,由于它们的身份已经在当前 session 中被证实。 尽管应用程序的许多部分仍然能够执行基于被记住身份 ID 的用户特定逻辑,像自定义视图,但它绝不应该执 行高度敏感的操作,除非用户通过执行一个成功的认证尝试来合法地验证自己的身份。 例如,一个检查来判断一个 Subject 可以访问财务信息应该几乎总是取决于 isAuthenticated(),而不是 isRemembered(),以保证一个预期和核实的身份。

注销

进行身份验证的反面是释放所有已知的的识别状态。当 Subject 完成了与应用程序的交互后,你可以调用 subject.logout()来释放所有的识别信息

    currentUser.logout();  //removes all identifying information an invalidates their session too. 

当你调用 logout,任何现有的 Session 都将会失效,而且任何身份都将会失去关联(例如,在 Web 应用程序 中,RememberMe cookie 也将被删除)。 在 Subject 注销后,该 Subject 的实例被再次认为是匿名的,当然,除了 Web 应用程序,它还可以重新用于 login 如果需要的话。

Web Application Notice 由于在 Web 应用程序记住身份往往是依靠 Cookies,然而 Cookies 只能在 Response 被 committed 之前被删除,所以强烈建议在调用 subject.logout()后立即将终端用户重定向到一个新的视图或页面。 这样能够保证任何与安全相关的Cookies都能像预期的一样被删除。这是HTTP cookies的功能限制,而不是Shiro 的。

登录验证过程分析

在这里插入图片描述

1.应用程序代码调用 Subject.login 方法,传递创建好的包含终端用户的 Principals(身份)和 Credentials(凭 证)的 AuthenticationToken 实例
    Subject.login(token); 
2.通常是 DelegatingSubject(或子类)委托应用程序的 SecurityManager 通过调用 securityManager.login(token)开始真正的验证工作
    Subject subject = this.securityManager.login(this, token);
3.SubjectManager 作为一个基本的“保护伞”的组成部分,接收 token 以及简单地委托给内部的 Authenticator 实例通过调用 authenticator.authenticate(token)。这通常是一个ModularRealmAuthenticator 实例, 支持在身份验证中协调一个或多个 Realm 实例。ModularRealmAuthenticator 本质上为 Apache Shiro 提供了 PAM-style 范式(其中在 PAM 术语中每个 Realm 都是一个’module’)。
    public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {
            AuthenticationInfo info;
            try {
                info = this.authenticate(token);
            } catch (AuthenticationException var7) {
                AuthenticationException ae = var7;
                ......
       
4.如果应用程序中配置了一个以上的 Realm,ModularRealmAuthenticator 实例将利用配置好的 AuthenticationStrategy 来启动 Multi-Realm 认证尝试。在 Realms 被身份验证调用之前,期间和以后, AuthenticationStrategy 被调用使其能够对每个 Realm 的结果作出反应。我们马上就会涉及到 AuthenticationStrategies

`

    protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
            this.assertRealmsConfigured();
            Collection<Realm> realms = this.getRealms();
            return realms.size() == 1 ? this.doSingleRealmAuthentication((Realm)realms.iterator().next(), authenticationToken) : this.doMultiRealmAuthentication(realms, authenticationToken);
        }  
5.认证策略

AuthenticationStrategy 组件来确定这些认证尝试的成功或失败条件。

    public interface AuthenticationStrategy {
        
        //1. 在任何 Realm 被调用之前被询问;  
        AuthenticationInfo beforeAllAttempts(Collection<? extends Realm> var1, AuthenticationToken var2) throws AuthenticationException;
        
        //2. 在一个单独的 Realm 的 getAuthenticationInfo 方法被调用之前立即被询问;
        AuthenticationInfo beforeAttempt(Realm var1, AuthenticationToken var2, AuthenticationInfo var3) throws AuthenticationException;
     
        //3. 在一个单独的 Realm 的 getAuthenticationInfo 方法被调用之后立即被询问;
        AuthenticationInfo afterAttempt(Realm var1, AuthenticationToken var2, AuthenticationInfo var3, AuthenticationInfo var4, Throwable var5) throws AuthenticationException;
    
        //4. 在所有的 Realm 被调用后询问
        AuthenticationInfo afterAllAttempts(AuthenticationToken var1, AuthenticationInfo var2) throws AuthenticationException;
    }

实现类

    public abstract class AbstractAuthenticationStrategy implements AuthenticationStrategy

三个子类,就是三个认证策略

AtLeastOneSuccessfulStrategy
如果一个(或更多)Realm 验证成功,则整体的 尝试被认为是成功的。如果没有一个验证成功,则整体尝试失败。

FirstSuccessfulStrategy
只有第一个成功地验证的 Realm 返回的信息将被 使用。所有进一步的 Realm 将被忽略。如果没有 一个验证成功,则整体尝试失败。

AllSucessfulStrategy
为了整体的尝试成功,所有配置的 Realm 必须验 证成功。如果没有一个验证成功,则整体尝试失 败

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值