我们做shiro框架经常会遇到这种情况,用户数量很多,又不在同一个表里,比如管理员一个表,用户一个表,商家一个表。这时我们就需要用到多realm来配置让他们用不同得realm来进行登录
首先来说思路,我们需要一个可以确定当前登录得用户是管理员,商家或者是普通用户的变量,所以我们需要改造一下token让他在登录得时候除了可以放用户名与密码还可以放一个用户登录类型来指定需要哪个realm来处理此次登录。然后我们就可以根据这个类型来指定用哪个realm来处理。
首先我们先写一个枚举类来存放登录类型。
public enum LoginType { USER("User"),ADMIN("Admin"),MERCHANTS("Merchants"); private String type; private LoginType(String type){ this.type=type; } @Override public String toString() { return this.type.toString(); } }
接下来我们来自定义一个token继承UsernamePasswordToken,让他可以存储登录类型
public class CustomizedToken extends UsernamePasswordToken { private String loginType; //增加构造函数,将登录类型加入进来 public CustomizedToken(final String username,final String password, String loginType) { super(username,password); this.loginType=loginType; } public String getLoginType() { return loginType; } public void setLoginType(String loginType) { this.loginType = loginType; } }
接下来我们需要重写shiro框架中的doAuthenticate()方法。
//首先需要写一个类来继承ModularRealmAuthenticator public class CustomizedModularRealmAuthenticator extends ModularRealmAuthenticator { //重写doAuthenticate()方法 @Override protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException { assertRealmsConfigured(); //获取当前登录的token将其强转成自定义token。 CustomizedToken token=(CustomizedToken) authenticationToken; //通过强转的自定义token可以通过getLoginType()的方法获取到当前登录类型,将类型保存起来 String LoginType=token.getLoginType(); //获取所有的realm的名字 Collection<Realm> realms=getRealms();//Collection<Realm>={"UserRealm","AdminRealm","MerchantsRealm"} System.out.println(realms); Collection<Realm> typeRealms=new ArrayList<>(); //通过循环去比对当前登录的用户名称包含在哪个realm里,用来决定用哪个realm来处理此次登录 for(Realm realm:realms) if(realm.getName().contains(LoginType)) typeRealms.add(realm); //判断符合条件的raelm有几个当只有一个realm符合条件的时候就使用这个realm //当多个realm符合条件会使用所有的realm但当前项目中只有使用一个 if(typeRealms.size()==1) return doSingleRealmAuthentication(typeRealms.iterator().next(),token); else return doMultiRealmAuthentication(typeRealms,token); } }
接下来的任务就是把我们重写的这个东西加到shiro框架中
@Bean public org.apache.shiro.mgt.SecurityManager securityManager(){ DefaultWebSecurityManager defaultSecurityManager=new DefaultWebSecurityManager(); defaultSecurityManager.setAuthenticator(new CustomizedModularRealmAuthenticator());//将我们重写的类放到框架中 //将三个realm放置shiro框架中 List<Realm> realms=new ArrayList<>(); realms.add(merchantsRealm()); realms.add(userRealm()); realms.add(adminRealm()); defaultSecurityManager.setRealms(realms); //将reidoscache装配到shiro框架中 defaultSecurityManager.setCacheManager(redisCacheManager()); //将redissession装配到shiro框架中 defaultSecurityManager.setSessionManager(sessionManager()); return defaultSecurityManager; }
到这里我们就算配置完成,接下来就是controller中的登录接口
//正常我们使用shiro登录是这样的 UsernamePasswordToken token=new UsernamePasswordToken(username,password); subject.login(token); //我们这里只需要用我们定义的token CustomizedToken token=new CustomizedToken(loginInput.getLoginName(),loginInput.getPassword(), LoginType.ADMIN.toString()); subject.login(token);
这样就会把登录类型加到shiro框架中。这样就完成了多realm的登录过程,realm里得详细细节在上篇文章中有描述,这里就不多阐述
感谢大佬的文章。
参考资料:https://blog.csdn.net/cckevincyh/article/details/79629022
