写完上篇随笔以后(链接).....我也想自己尝试一下写一个Strategy.....Shiro自带了3个Strategy,教程(链接)里作者也给了2个.....我想写个都不一样的策略.....看来看去....决定写个LastSuccessfulStrategy好了...顾名思义就是返回最后一个Realm验证成功的AuthenticationInfo的信息...
1 package com.github.zhangkaitao.shiro.chapter2.authenticator.strategy; 2 3 import org.apache.shiro.authc.AuthenticationException; 4 import org.apache.shiro.authc.AuthenticationInfo; 5 import org.apache.shiro.authc.AuthenticationToken; 6 import org.apache.shiro.authc.pam.AbstractAuthenticationStrategy; 7 import org.apache.shiro.realm.Realm; 8 import org.apache.shiro.util.CollectionUtils; 9 10 public class LastSuccessfulStrategy extends AbstractAuthenticationStrategy { 11 @Override 12 protected AuthenticationInfo merge(AuthenticationInfo info, 13 AuthenticationInfo aggregate) { 14 // TODO Auto-generated method stub 15 if (info != null && !CollectionUtils.isEmpty(info.getPrincipals())) 16 return info; 17 else 18 return aggregate; 19 } 20 21 @Override 22 public AuthenticationInfo afterAttempt(Realm realm, 23 AuthenticationToken token, AuthenticationInfo singleRealmInfo, 24 AuthenticationInfo aggregateInfo, Throwable t) 25 throws AuthenticationException { 26 // TODO Auto-generated method stub 27 return merge(singleRealmInfo, aggregateInfo); 28 } 29 30 @Override 31 public AuthenticationInfo afterAllAttempts(AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException { 32 //we know if one or more were able to succesfully authenticate if the aggregated account object does not 33 //contain null or empty data: 34 if (aggregate == null || CollectionUtils.isEmpty(aggregate.getPrincipals())) { 35 throw new AuthenticationException("Authentication token of type [" + token.getClass() + "] " + 36 "could not be authenticated by any configured realms. Please ensure that at least one realm can " + 37 "authenticate these tokens."); 38 } 39 40 return aggregate; 41 } 42 }
我的想法是这样的...只要Realm返回的info不为空,就把它作为aggregate储存起来...否则直接返回aggregate....所以我override了merge方法...并在afterAttemp里调用它....
然后所有Realm都处理完毕以后..如果aggregate是null...说明所有Realm都验证失败了...那么应该抛出异常....这里逻辑我就直接抄AtLeastOneSuccessfulStrategy类的代码了...
测试代码直接修改教程的就行了
1 @Test 2 public void testHelloworld2() { 3 // 1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager 4 Factory<org.apache.shiro.mgt.SecurityManager> factory = new IniSecurityManagerFactory( 5 "classpath:shiro2.ini"); 6 7 // 2、得到SecurityManager实例 并绑定给SecurityUtils 8 org.apache.shiro.mgt.SecurityManager securityManager = factory 9 .getInstance(); 10 SecurityUtils.setSecurityManager(securityManager); 11 12 // 3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证) 13 Subject subject = SecurityUtils.getSubject(); 14 UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123"); 15 16 try { 17 // 4、登录,即身份验证 18 subject.login(token); 19 } 20 catch (AuthenticationException e) { 21 // 5、身份验证失败 22 } 23 24 Assert.assertEquals(true, subject.isAuthenticated()); // 断言用户已经登录 25 System.out.println(subject.getPrincipal()); 26 27 // 6、退出 28 subject.logout(); 29 }
shiro2.ini也修改自教程
1 [main] 2 #指定securityManager的authenticator实现 3 authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator 4 securityManager.authenticator=$authenticator 5 6 #指定securityManager.authenticator的authenticationStrategy 7 lastSuccessfulStrategy=org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy 8 securityManager.authenticator.authenticationStrategy=$lastSuccessfulStrategy 9 10 myRealm1=com.github.zhangkaitao.shiro.chapter2.realm.MyRealm1 11 myRealm2=com.github.zhangkaitao.shiro.chapter2.realm.MyRealm2 12 myRealm3=com.github.zhangkaitao.shiro.chapter2.realm.MyRealm3 13 securityManager.realms=$myRealm1,$myRealm3,$myRealm2
3个Realm我就不贴了...和教程是一样的....
这样我自己的LastSuccessfulStrategy策略就完成啦O(∩_∩)O哈!