Shiro身份认证
2020-05-27 本文已影响0人
李白不喜欢杜甫
获取Subjects
1.获取认证数据或者证书
/Example using most common scenario of username/password pair:
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//"Remember Me" built-in:
token.setRememberMe(true);
使用[UsernamePasswordToken](http://shiro.apache.org/static/current/apidocs/org/apache/shiro/authc/UsernamePasswordToken.html),它支持最常见的用户名/密码身份验证方法。这是Shiro的[org.apache.shiro.authc.AuthenticationToken](http://shiro.apache.org/static/current/apidocs/org/apache/shiro/authc/AuthenticationToken.html)接口的实现,该接口是Shiro的身份验证系统用来表示提交的主体和凭据的基本接口。
在此需要注意的重要一点是Shiro不在乎您如何获取此信息:数据可能是由提交HTML表单的用户获取的,或者是从HTTP标头中检索的,或者是从Swing或Flex中读取的GUI密码形式,或通过命令行参数。从应用程序最终用户收集信息的过程与Shiro的AuthenticationToken概念完全脱钩。
2.提交认证数据或凭证
Subject currentUser = SecurityUtils.getSubject();
currentUser.login(token);
在获取当前执行的之后`Subject`,我们进行一次[`login`](http://shiro.apache.org/static/current/apidocs/org/apache/shiro/subject/Subject.html#login-org.apache.shiro.authc.AuthenticationToken-)调用,传入`AuthenticationToken`我们之前创建的实例。该`login`方法的调用有效地表示身份验证尝试。
3.认证成功或失败处理
如果该login
方法安静地返回,就可以了-我们完成了!在Subject
已经通过认证。应用程序线程可以不间断地继续运行,对的所有进一步调用SecurityUtils.getSubject()
将返回已认证的Subject
实例,对的任何调用都subject.
isAuthenticated()
将返回true
。
但是,如果登录尝试失败怎么办?例如,如果最终用户提供了错误的密码,或者访问了系统太多次并且可能他们的帐户被锁定了怎么办?
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则可以创建自定义来表示特定的故障情况。
[注意:尽管您的代码可以对特定的异常做出反应并在必要时执行逻辑,但是安全性最佳实践是仅在发生失败(例如,“用户名或密码不正确”)时向最终用户显示通用失败消息。这样可确保没有任何特定信息可供尝试攻击媒介的黑客使用。]
认证和记住的区别
如上面的例子所示,除了正常的登录过程之外,Shiro还支持“记住我”的概念。此时值得指出的是,Shiro非常精确地区分了记忆中的主题和实际经过验证的主题:
- Remembered: 记住的对象不是匿名的,并且具有已知的身份(即subject.getPrincipals()不是空的)。但此身份将从上一会话期间的上一次身份验证中记住。如果主题.isremembeed()返回true。
-Authenticated:已验证的主题是在主题的当前会话期间已成功验证的主题(即,已调用登录方法而未引发异常)。如果subject.isAuthenticated()返回true。
【注意:记住和已认证状态是互斥的-一个true值表示另一个false值,反之亦然。】
Remembered与Authenticated有什么不同:
“认证”这个词有很强的证明的含义。也就是说,有一个预期的保证,那就是主体已经证明他们是他们所说的那个人。
当用户仅通过与应用程序的前一次交互被记住时,证明状态不再存在:记住的标识使系统知道该用户可能是谁,但在现实中,无法绝对保证记住的主题是否代表预期的用户。一旦主体经过身份验证,它们就不再被认为只会被记住,因为它们的身份将在当前会话期间得到验证。
因此,尽管应用程序的许多部分仍然可以基于记住的主体(例如自定义视图)执行特定于用户的逻辑,但在用户通过执行成功的身份验证尝试合法地验证其身份之前,应用程序通常不应该执行高度敏感的操作。
例如,检查主题是否可以访问财务信息几乎总是依赖于isAuthenticated(),而不是isRemembered(),以确保预期的和经过验证的身份。
以下是一个相当常见的场景,有助于说明Remembered和Authenticated之间存在差异,假设您使用的是Amazon.com。您已经成功登录并向您的数据库添加了一些书籍。第二天当你来上班的时候,你意识到你没有完成你的购买,所以你回去了,但是,如果您尝试访问帐户以更新信用卡信息以购买图书,会发生什么情况?当亚马逊“记住”您(isRemembered()== true)时,它不能保证您实际上就是您(例如,某个同事正在使用您的计算机)。因此,在您执行敏感操作(如更新信用卡信息)之前,亚马逊会强迫您登录,以便他们保证您的身份。登录后,您的身份已通过验证,并且isAuthenticated()现在为true。这种情况在许多类型的应用程序中经常发生,因此该功能内置于Shiro中,因此您可以将其用于自己的应用程序。现在,是否使用isRemembered() 或isAuthenticated()自定义视图和工作流取决于您自己,但是Shiro将保留此基本状态,以备不时之需。
注销
认证的相反是释放所有已知的识别状态。当`Subject`完成与应用程序交互,你可以叫`subject.`[`logout()`]放弃所有的身份信息:
currentUser.logout(); //removes all identifying information and invalidates their session too.
当您调用时logout,任何现有的Session都将无效,并且所有身份都将被取消关联(例如,在Web应用程序中,RememberMe cookie也将被删除)。经过Subject日志出的Subject实例再次审议匿名的,并且,除了Web应用程序,可以重新使用login,如果需要的一次。
【注意:由于Web应用程序中记住的身份通常与cookie保持在一起,并且cookie只能在提交响应主体之前删除,因此强烈建议在调用后立即将最终用户重定向到新视图或页面subject.logout()。这保证了所有与安全性有关的cookie均会按预期删除。这是HTTP cookie的功能限制,而不是Shiro的限制。】
认证顺序

1.应用程序代码调用该Subject.login方法,并传入AuthenticationToken表示最终用户的主体和凭据的构造实例。
2.`Subject`实例(通常是一个[`DelegatingSubject`](http://shiro.apache.org/static/current/apidocs/org/apache/shiro/subject/support/DelegatingSubject.html)(或子类))`SecurityManager`通过调用来委托应用程序,实例`securityManager.login(token)`从此处开始实际的身份验证工作。
3. `SecurityManager`作为基本的“伞”组件,接收令牌并[`Authenticator`](http://shiro.apache.org/static/current/apidocs/org/apache/shiro/authc/Authenticator.html)通过调用来简单地委派给其内部实例[`authenticator.authenticate(token)`](http://shiro.apache.org/static/current/apidocs/org/apache/shiro/authc/Authenticator.html#authenticate-org.apache.shiro.authc.AuthenticationToken-)。这几乎总是一个[`ModularRealmAuthenticator`](http://shiro.apache.org/static/current/apidocs/org/apache/shiro/authc/pam/ModularRealmAuthenticator.html)实例,它支持`Realm`在身份验证期间协调一个或多个实例。在`ModularRealmAuthenticator`本质上提供一个[PAM](https://en.wikipedia.org/wiki/Pluggable_Authentication_Modules)为Apache四郎(其中每个样式的范例`Realm`是在PAM术语一个“模块”)。
4.如果`Realm`为该应用程序配置了多个,则该`ModularRealmAuthenticator`实例将`Realm`使用其configureed 发起多次身份验证尝试[`AuthenticationStrategy`](http://shiro.apache.org/static/current/apidocs/org/apache/shiro/authc/pam/AuthenticationStrategy.html)。在`Realms`调用进行身份验证之前,期间和之后,将调用,`AuthenticationStrategy`以允许它对每个Realm的结果做出反应。我们将`AuthenticationStrategies`尽快覆盖。
5.`Realm`请咨询每个配置,以查看是否[`supports`](http://shiro.apache.org/static/current/apidocs/org/apache/shiro/realm/Realm.html#supports-org.apache.shiro.authc.AuthenticationToken-)已提交`AuthenticationToken`。如果是这样,支持的Realm [`getAuthenticationInfo`](http://shiro.apache.org/static/current/apidocs/org/apache/shiro/realm/Realm.html#getAuthenticationInfo-org.apache.shiro.authc.AuthenticationToken-)方法将与Submitted一起调用`token`。该`getAuthenticationInfo`方法有效地表示针对该特定对象的单个身份验证尝试`Realm`。我们将`Realm`很快介绍身份验证行为。
认证器
如前所述,Shiro `SecurityManager`实现默认使用[`ModularRealmAuthenticator`](http://shiro.apache.org/static/current/apidocs/org/apache/shiro/authc/pam/ModularRealmAuthenticator.html)实例。它们`ModularRealmAuthenticator`同样支持具有单个领域以及具有多个领域的应用程序。
在单一领域的应用程序中,ModularRealmAuthenticator
将Realm
直接调用单一领域。如果配置了两个或更多领域,它将使用一个AuthenticationStrategy
实例来协调尝试的发生方式。我们将在下面介绍AuthenticationStrategies。
如果您希望SecurityManager
使用自定义Authenticator
实现来配置,则可以在shiro.ini
以下示例中进行配置:(在Maven使用realm注入)
[main]
...
authenticator = com.foo.bar.CustomAuthenticator
securityManager.authenticator = $authenticator
领域认证
当程序配有多个数据源时,`ModularRealmAuthenticator`依赖于内部[`AuthenticationStrategy`]组件来确定认证尝试成功或失败的条件。
例如,如果只有一个Realm认证`AuthenticationToken`成功,而其他所有认证都失败,那么认证尝试是否被视为成功?还是必须所有领域都成功进行身份验证,才能将整体尝试视为成功?或者,如果某个领域成功通过身份验证,是否有必要进一步咨询其他领域?一种`AuthenticationStrategy`使基于应用程序的需要作出适当的决定。
AuthenticationStrategy是一个无状态组件,在身份验证尝试期间会被查询4次(这4种交互所需的任何必要状态都将作为方法参数给出):
1. 在任何领域被调用之前
2. 在`getAuthenticationInfo`调用单个Realm 方法之前
3. 在`getAuthenticationInfo`调用单个领域的方法之后
4. 在所有领域都被调用之后
另外,`AuthenticationStrategy`负责将每个成功Realm的结果汇总并“捆绑”为单个[`AuthenticationInfo`]表示形式。这个最终的聚合`AuthenticationInfo`实例是该`Authenticator`实例返回的内容,也是Shiro用来表示`Subject`的最终身份(又称为Principals)的东西。
Shiro有3种具体的AuthenticationStrategy实现方式:

在ModularRealmAuthenticator默认的AtLeastOneSuccessfulStrategy实施,因为这是最常用的策略所需。但是,您可以根据需要配置其他策略:
```
[main]
authcStrategy = org.apache.shiro.authc.pam.FirstSuccessfulStrategy
securityManager.authenticator.authenticationStrategy = $authcStrategy
```