Shiro User Manual-Authentication

阅读更多
1. Authentication
Shiro User Manual-Authentication_第1张图片
Authentication,认证,即身份验证,证明一个用户是谁。用户想要证明其身份,就需要提供身份信息,以及系统可以识别的标识证明。这需要向Shiro提供用户的principals和credentials来验证其是否和系统匹配。

1.1 Principals
即Subject的识别属性。 Principals可以是任何可以识别Subject的事物。比如,名,姓,用户名,身份证号等等。当然了,姓不能很好唯一的识别一个Subject。因此,对于应用中,最好的principals就是用户名或者email。

1.1.1 Primary Principal
  虽然可以使用任意数量的principals,对于一个应用,最好有一个主要的principal,一个简易的值来唯一的标识Subject。通常使用用户名,emial或者唯一的userid。

1.2 Credentials
  即加密的数值,用来证明其对Subject所声明的身份。通常,为密码,生物识别数据如指纹,视网膜扫描等。
  一般来说,principal/credential即指用户名和密码。用户名指明其身份,密码进行身份验证。如果提交的密码符合系统的验证,系统就可以认为这个用户是合法的。

2. Authenticating Subjects
验证Subject分3步。
a. 收集提交的principals和credentials
b. 提交principals和credentials进行验证
c. 如果提交成功,允许访问,否则重新提交或不允许访问
以下代码演示了使用Shiro的API对于这三部分的操作。
Step 1: Collect the Subject's principals and credentials
//Example using most common scenario of username/password pair:
UsernamePasswordToken token = new UsernamePasswordToken(username, password);

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

  这个例子中,我们使用UsernamePasswordToken,它支持通常的用户名和密码的验证。它是org.apache.shiro.authc.AuthenticationToken的一个实现。AuthenticationToken接口表示Shiro系统认证中提交的principals和credentials.
  需要注意的是,Shiro不关心你如何获取的这些信息:可以从用户的表单提交,HTTP的头信息,Swing,Flex GUI表单,或者命令行。也可以任意构建AuthenticationToken,因为它是协议无关的。
从例子中可以看出,在认证请求时,我们想使用Shiro的"Remember Me"服务。它表示Shiro记住了当前的用户身份。
Step 2: Submit the principals and credentials
  收集了principals和credentials,并构建为AuthenticationToken实例,我们需要提交这个token(令牌)让Shiro进行认证。
Subject currentUser = SecurityUtils.getSubject();

currentUser.login(token);

  获取了当前操作的Subject后,我们传入token,调用了login方法。一次login方法的调用,就代表尝试一次认证。
Step 3: Handling Success or Failure
  如果login方法无任何返回,表示我们的认证成功了。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。

2.1 Login Failure Tip
  虽然这些异常类可以很好的反映出业务逻辑,但实践中,只需要给终端用户显示简单的提示消息即可,比如"用户名或密码错误",以防止被试图带有攻击倾向的黑客所获取。

2.2 Remembered vs. Authenticated
  如上面的例子,Shiro除了登陆,还支持 "remember me"的概念。这里需要指出的是,Shiro的remembered Subject和authenticated Subject有明显的区别。
Remembered:
  一个remembered Subject,不能是匿名的,其被上一次会话所认证并记忆,subject.getPrincipals方法返回不为空。只有subject.isRemembered()返回true时,才被认为是remembered subject。
Authenticated:
  一个authenticated Subject表示,其被当前会话成功的认证过(调用login方法没有任何异常信息)。只有当subject.isAuthenticated()返回true时,才被认为是authenticated subject。

2.3 Mutually Exclusive
  Remembered和authenticated两种状态是互斥的。一个true,另一个即为false,反之亦然。

2.4 Why the distinction?
  authentication一词,有强烈的证明寓意。即,必须保证Subject被认证过。当一个用户被上一次的应用会话所记忆,认证的状态已不存在了,被记忆的用户标识只能告诉系统,这个用户可能是谁,但实质上并不能完全保证它就是那个用户。然而,一个authenticated subject,不单单被认为是记忆着的,而且必须保证在当前会话中被认证过。尽管应用的有些功能可以使用记忆着的principals来执行一些用户的逻辑操作,比如自定义视图,但是在用户被合法性认证前,最好不要执行一些敏感的操作。比如,对于金融信息的访问,使用subject的isAuthenticated()以保证它的安全和合法性,而非isRemembered()。

2.5 Logging Out
  当subject和应用交互完成后,需要销毁这些认证的信息。
currentUser.logout(); //removes all identifying information and invalidates their session too.

  当调用logout方法后,session失效,所有的认证信息都无效了(web应用中,RememberMe的cookie也被删除),subject实例变为匿名的(在web应用中,其还可以重用。)

2.6 Web Application Notice
  由于web应用中,remembered的标识保存在cookie中,而cookie只有在response提交前才能被删除,强烈建议在调用logout方法后,立刻让终端用户跳转到一个新的视图或页面,这样,才能保证和信息安全相关的cookie被删除掉。这是由HTTP的cookie所限而非Shiro。

2.7 Authentication Sequence
  直到现在,我们只看到了应用中认证subject,那么,接下来我们要看一下Shiro内部的认证流程。下面架构图左边的部分,就是和认证相关的,数字代表了验证的步骤。
Shiro User Manual-Authentication_第2张图片
step1:从终端用户获取principals和credentials来构建AuthenticationToken实例,调用subject.login方法。
step2: subject实现类DelegatingSubject(或子类)委托给应用的SecurityManager,调用securityManager的login(token)方法。
step3: SecurityManager接受到token后,委托其内部的Authenticator,调用authenticator的authenticate(token)方法。
step4: 如果配置多个Realm,ModularRealmAuthenticator(Realm的默认实现)利用其配置的AuthenticationStrategy决定如何对Realm进行认证。如果应用中只配置了一个Realm,就不需要AuthenticationStrategy。
step5: 每个Realm都要检查其是否支持提交的token,如果支持,getAuthenticationInfo方法将被调用,返回封装了token的AuthenticationInfo实例。

3. Authenticator
  SecurityManager默认实现中都使用了ModularRealmAuthenticator。 ModularRealmAuthenticator同时支持单Realm和多Realm。
如果想自定义的Authenticator,可以在shiro.ini中这样做:
[main]
...
authenticator = com.foo.bar.CustomAuthenticator

securityManager.authenticator = $authenticator


3.1 AuthenticationStrategy
在单Realm应用中,ModularRealmAuthenticator直接调用Reaml。在多Realm中,它使用AuthenticationStrategy来决定如何判断认证的成功与否。比如,如果只有一个Realm验证成功,其他的全部失败,认证是成功么?还是所有的Realm认证都必须要成功才算认证成功?亦或一个Realm验证成功,是否还需要调用其他Realm?AuthenticationStrategy会根据应用的需求来决定如何进行验证。AuthenticationStrategy为无状态组件,每次认证请求,需要调用它四次。
1.在Realms被调用前。
2.在每个Realm的getAuthenticationInfo之前
3.在每个Realm的getAuthenticationInfo之后
4.在所有Realms被调用后。
AuthenticationStrategy汇集成功认证的Realm结果,并将它们封装为AuthenticationInfo。AuthenticationInfo就是Authenticator实例所最终返回的结果,也就是Subject的标识(或Principals)。

Shiro中有3个AuthenticationStrategy实现:
AuthenticationStrategy class Description
AtLeastOneSuccessfulStrategy   If one (or more) Realms authenticate successfully, the overall attempt is considered successful. If none authenticate succesfully, the attempt fails.
FirstSuccessfulStrateg      Only the information returned from the first successfully authenticated Realm will be used. All further Realms will be ignored. If none authenticate successfully, the attempt fails.
AllSuccessfulStrategy       All configured Realms must authenticate successfully for the overall attempt to be considered successful. If any one does not authenticate successfully, the attempt fails.

AtLeastOneSuccessfulStrategy是ModularRealmAuthenticator中AuthenticationStrategy的默认实现。
[main]
...
authcStrategy = org.apache.shiro.authc.pam.FirstSuccessfulStrategy

securityManager.authenticator.authenticationStrategy = $authcStrategy


3.2 Custom AuthenticationStrategy
  如果想自定义AuthenticationStrategy,可以继承org.apache.shiro.authc.pam.AbstractAuthenticationStrategy。

3.3 Implicit Ordering
如果使用Shiro的ini配置方式,需要指定Realm对于AuthenticationToken的处理顺序。在shiro.ini中,Realm的处理顺序就是其在文件中定义的顺序。
blahRealm = com.company.blah.Realm
...
fooRealm = com.company.foo.Realm
...
barRealm = com.company.another.Realm


在认证处理时,blahRealm,fooRealm,barRealm会依次被调用。
等同于:
securityManager.realms = $blahRealm, $fooRealm, $barRealm


3.4 Explicit Ordering
  如果想显示定义Realms的顺序,可以设置securityManager的realms属性。还使用上面的例子,但是这次,把blahRealm放在最后:
blahRealm = com.company.blah.Realm
...
fooRealm = com.company.foo.Realm
...
barRealm = com.company.another.Realm

securityManager.realms = $fooRealm, $barRealm, $blahRealm

在认证处理时,fooRealm,barRealm,blahRealm会依次被调用。

3.5 Explicit Realm Inclusion
如果显式配置了securityManager.realms属性,只有配置的realms才有效。也就是说,如果你在ini文件中定义了5个realms,而只有3个被securityManager的realms属性引用,那么只有这三个才是有效的。这和隐式定义realm不同,隐式的realm将全部有效。
  • Shiro User Manual-Authentication_第3张图片
  • 大小: 26.1 KB
  • Shiro User Manual-Authentication_第4张图片
  • 大小: 88.4 KB
  • 查看图片附件

你可能感兴趣的:(Shiro,Security,Authentication,Authorization)