当前位置:   article > 正文

关于身份认证中的Authenticator及AuthenticationStrategy_custommodularrealmauthenticator 策略atleastonesucces

custommodularrealmauthenticator 策略atleastonesuccessfulstrategy


在流程图3中,有Authenticator和AuthenticationStrategy2个接口。

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

        它只有一个方法:

  1. public AuthenticationInfo authenticate(AuthenticationToken authenticationToken)
  2. throws AuthenticationException;

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

选中AuthenticationInfo,按住Ctrl+t,可以看到它的继承体系。

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

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

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

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

 

ModularRealmAuthenticator默认使用AtLeastOneSuccessfulStrategy策略。


一个例子:

假设我们有三个realm:

myRealm1: 用户名/密码为zhang/123时成功,且返回身份/凭据为zhang/123;

myRealm2: 用户名/密码为wang/123时成功,且返回身份/凭据为wang/123;

myRealm3: 用户名/密码为zhang/123时成功,且返回身份/凭据为zhang@163.com/123,和myRealm1不同的是返回时的身份变了;


三个reaml文件如下:

  1. package com.lgy.shiro;
  2. import org.apache.shiro.authc.AuthenticationException;
  3. import org.apache.shiro.authc.AuthenticationInfo;
  4. import org.apache.shiro.authc.AuthenticationToken;
  5. import org.apache.shiro.authc.IncorrectCredentialsException;
  6. import org.apache.shiro.authc.SimpleAuthenticationInfo;
  7. import org.apache.shiro.authc.UnknownAccountException;
  8. import org.apache.shiro.authc.UsernamePasswordToken;
  9. import org.apache.shiro.realm.Realm;
  10. public class MyRealm1 implements Realm {
  11. public String getName() {
  12. return "myrealm1";
  13. }
  14. public boolean supports(AuthenticationToken token) {
  15. return token instanceof UsernamePasswordToken; //仅支持UsernamePasswordToken类型的Token
  16. }
  17. public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
  18. String username = (String)token.getPrincipal(); //得到用户名
  19. String password = new String((char[])token.getCredentials()); //得到密码
  20. if(!"zhang".equals(username)) {
  21. throw new UnknownAccountException(); //如果用户名错误
  22. }
  23. if(!"123".equals(password)) {
  24. throw new IncorrectCredentialsException(); //如果密码错误
  25. }
  26. //如果身份认证验证成功,返回一个AuthenticationInfo实现;
  27. return new SimpleAuthenticationInfo(username, password, getName());
  28. }
  29. }
  30. package com.lgy.shiro;
  31. import org.apache.shiro.authc.AuthenticationException;
  32. import org.apache.shiro.authc.AuthenticationInfo;
  33. import org.apache.shiro.authc.AuthenticationToken;
  34. import org.apache.shiro.authc.IncorrectCredentialsException;
  35. import org.apache.shiro.authc.SimpleAuthenticationInfo;
  36. import org.apache.shiro.authc.UnknownAccountException;
  37. import org.apache.shiro.authc.UsernamePasswordToken;
  38. import org.apache.shiro.realm.Realm;
  39. public class MyRealm2 implements Realm {
  40. public String getName() {
  41. return "myrealm2";
  42. }
  43. public boolean supports(AuthenticationToken token) {
  44. return token instanceof UsernamePasswordToken; //仅支持UsernamePasswordToken类型的Token
  45. }
  46. public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
  47. String username = (String)token.getPrincipal(); //得到用户名
  48. String password = new String((char[])token.getCredentials()); //得到密码
  49. if(!"wang".equals(username)) {
  50. throw new UnknownAccountException(); //如果用户名错误
  51. }
  52. if(!"123".equals(password)) {
  53. throw new IncorrectCredentialsException(); //如果密码错误
  54. }
  55. //如果身份认证验证成功,返回一个AuthenticationInfo实现;
  56. return new SimpleAuthenticationInfo(username, password, getName());
  57. }
  58. }
  59. package com.lgy.shiro;
  60. import org.apache.shiro.authc.AuthenticationException;
  61. import org.apache.shiro.authc.AuthenticationInfo;
  62. import org.apache.shiro.authc.AuthenticationToken;
  63. import org.apache.shiro.authc.IncorrectCredentialsException;
  64. import org.apache.shiro.authc.SimpleAuthenticationInfo;
  65. import org.apache.shiro.authc.UnknownAccountException;
  66. import org.apache.shiro.authc.UsernamePasswordToken;
  67. import org.apache.shiro.realm.Realm;
  68. public class MyRealm3 implements Realm {
  69. public String getName() {
  70. return "myrealm3";
  71. }
  72. public boolean supports(AuthenticationToken token) {
  73. return token instanceof UsernamePasswordToken; //仅支持UsernamePasswordToken类型的Token
  74. }
  75. public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
  76. String username = (String)token.getPrincipal(); //得到用户名
  77. String password = new String((char[])token.getCredentials()); //得到密码
  78. if(!"zhang".equals(username)) {
  79. throw new UnknownAccountException(); //如果用户名错误
  80. }
  81. if(!"123".equals(password)) {
  82. throw new IncorrectCredentialsException(); //如果密码错误
  83. }
  84. //如果身份认证验证成功,返回一个AuthenticationInfo实现;
  85. return new SimpleAuthenticationInfo(username + "163@qq.com", password, getName());
  86. }
  87. }


封装的login代码如下:

  1. private void login(String configFile) {
  2. //1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
  3. Factory<org.apache.shiro.mgt.SecurityManager> factory =
  4. new IniSecurityManagerFactory(configFile);
  5. //2、得到SecurityManager实例 并绑定给SecurityUtils
  6. org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();
  7. SecurityUtils.setSecurityManager(securityManager);
  8. //3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
  9. Subject subject = SecurityUtils.getSubject();
  10. UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
  11. subject.login(token);
  12. }
  13. @After
  14. public void tearDown() throws Exception {
  15. ThreadContext.unbindSubject();//退出时请解除绑定Subject到线程 否则对下次测试造成影响
  16. }


上面说的:

默认策越(ModularRealmAuthenticator默认使用AtLeastOneSuccessfulStrategy策略。)DEMO

ini文件:

  1. [main]
  2. #声明一个realm
  3. myRealm1=com.lgy.shiro.MyRealm1
  4. myRealm2=com.lgy.shiro.MyRealm2
  5. myRealm3=com.lgy.shiro.MyRealm3
  6. #指定securityManager的realms实现
  7. securityManager.realms=$myRealm1,$myRealm2,$myRealm3

测试如下:

  1. @Test
  2. public void testStrategyWithdefault() {
  3. login("classpath:shiro-auth-default.ini");
  4. // login("classpath:shiro-realm.ini");
  5. Subject subject = SecurityUtils.getSubject();
  6. /*
  7. boolean b = subject.isAuthenticated();
  8. System.out.println(b);*/
  9. //得到一个身份集合,其包含了Realm验证成功的身份信息
  10. PrincipalCollection principalCollection = subject.getPrincipals();
  11. System.out.println(principalCollection.asList().size()); //返回所有的身份凭证信息
  12. //Assert.assertEquals(2, principalCollection.asList().size());
  13. }

      验证信息是zhang/123, myRealm1和myRealm2是能通过的,打印返回的size为2,正如前面所说的:只要有一个Realm验证成功即可,和FirstSuccessfulStrategy不同,返回所有Realm身份验证成功的认证信息;



FirstSuccessfulStrategy策越,demo如下:

ini文件:

  1. [main]
  2. #指定securityManager的authenticator实现
  3. authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
  4. securityManager.authenticator=$authenticator
  5. #指定securityManager.authenticator的authenticationStrategy
  6. firstSuccessfulStrategy=org.apache.shiro.authc.pam.FirstSuccessfulStrategy
  7. securityManager.authenticator.authenticationStrategy=$firstSuccessfulStrategy
  8. #声明一个realm
  9. myRealm1=com.lgy.shiro.MyRealm1
  10. myRealm2=com.lgy.shiro.MyRealm2
  11. myRealm3=com.lgy.shiro.MyRealm3
  12. #指定securityManager的realms实现
  13. securityManager.realms=$myRealm1,$myRealm2,$myRealm3

测试代码:

  1. @Test
  2. public void testStrategyWithdefirst() {
  3. login("classpath:shiro-auth-first.ini");
  4. Subject subject = SecurityUtils.getSubject();
  5. System.out.println(subject.isAuthenticated());
  6. PrincipalCollection principalCollection = subject.getPrincipals();
  7. System.out.println(principalCollection.asList().size());
  8. }
      验证信息是zhang/123, myRealm1和myRealm2是能通过的,打印返回的size为1,正如前面所说的只要有一个Realm验证成功即可,只返回第一个Realm身份验证成功的认证信息,其他的忽略;


AllSuccessfulStrategy测试,demo如下:

ini文件:

  1. [main]
  2. #指定securityManager的authenticator实现
  3. authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
  4. securityManager.authenticator=$authenticator
  5. #指定securityManager.authenticator的authenticationStrategy
  6. allSuccessfulStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategy
  7. securityManager.authenticator.authenticationStrategy=$allSuccessfulStrategy
  8. #声明一个realm
  9. myRealm1=com.lgy.shiro.MyRealm1
  10. myRealm2=com.lgy.shiro.MyRealm2
  11. myRealm3=com.lgy.shiro.MyRealm3
  12. #指定securityManager的realms实现
  13. securityManager.realms=$myRealm1,$myRealm2,$myRealm3


测试文件:

  1. @Test
  2. public void testStrategyWithdeAll() {
  3. login("classpath:shiro-auth-all.ini");
  4. Subject subject = SecurityUtils.getSubject();
  5. System.out.println(subject.isAuthenticated());
  6. PrincipalCollection principalCollection = subject.getPrincipals();
  7. System.out.println(principalCollection.asList().size());
  8. }

       验证信息是zhang/123, myRealm1和myRealm3是能通过的,但是myRealm2不是通过,所以会抛出异常,测试部通过。 将myRealm2中的wang改为zhang,所以验证能通过,打印为2,为什么?因为返回凭证中myRealm1和myRealm2一样被当做同一个凭证。











声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/124299
推荐阅读
相关标签
  

闽ICP备14008679号