博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
springboot shiro 多realm配置认证、授权
阅读量:5775 次
发布时间:2019-06-18

本文共 11306 字,大约阅读时间需要 37 分钟。

shiro进行登录认证和权限管理的实现。其中需求涉及使用两个角色分别是:门店,公司。现在要两者实现分开登录。即需要两个Realm——MyShiroRealmSHOP和MyShiroRealmCOMPANY,分别处理门店,公司的验证功能。

但是正常情况下,当定义了多个Realm,无论是门店登录还是公司登录,都会由这两个Realm共同处理。这是因为,当配置了多个Realm时,我们通常使用的认证器是shiro自带的org.apache.shiro.authc.pam.ModularRealmAuthenticator,其中决定使用的Realm的是doAuthenticate()方法,源代码如下:

protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {        assertRealmsConfigured();        Collection
realms = getRealms(); if (realms.size() == 1) { return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken); } else { return doMultiRealmAuthentication(realms, authenticationToken); } }

  

上述代码的意思就是如果有多个Realm就会使用所有配置的Realm。 只有一个的时候,就直接使用当前的Realm。

为了实现需求,我会创建一个org.apache.shiro.authc.pam.ModularRealmAuthenticator的子类,并重写doAuthenticate()方法,让特定的Realm完成特定的功能。如何区分呢?我会同时创建一个org.apache.shiro.authc.UsernamePasswordToken的子类,在其中添加一个字段VirtualType,用来标识登录的类型,即是门店登录还是公司登录。具体步骤如下:

public enum VirtualType {    COMPANY,        // 公司    SHOP            // 门店}

  接下来新建org.apache.shiro.authc.UsernamePasswordToken的子类UserToken

import org.apache.shiro.authc.UsernamePasswordToken;public class UserToken extends UsernamePasswordToken {    private VirtualType virtualType;    public UserToken(final String username, final String password, VirtualType virtualType) {        super(username, password);        this.virtualType = virtualType;    }    public VirtualType getVirtualType() {        return virtualType;    }    public void setVirtualType(VirtualType virtualType) {        this.virtualType = virtualType;    }}

  新建org.apache.shiro.authc.pam.ModularRealmAuthenticator的子类UserModularRealmAuthenticator:

import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.pam.ModularRealmAuthenticator;import org.apache.shiro.realm.Realm;public class UserModularRealmAuthenticator extends ModularRealmAuthenticator {    private static final Logger logger = LoggerFactory.getLogger(UserModularRealmAuthenticator.class);    @Override    protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken)            throws AuthenticationException {        logger.info("UserModularRealmAuthenticator:method doAuthenticate() execute ");        // 判断getRealms()是否返回为空        assertRealmsConfigured();        // 强制转换回自定义的CustomizedToken        UserToken userToken = (UserToken) authenticationToken;        // 登录类型        VirtualType virtualType = userToken.getVirtualType();        // 所有Realm        Collection
realms = getRealms(); // 登录类型对应的所有Realm Collection
typeRealms = new ArrayList<>(); for (Realm realm : realms) { if (realm.getName().contains(virtualType.toString()))  // 注:这里使用类名包含枚举,区分realm typeRealms.add(realm); } // 判断是单Realm还是多Realm if (typeRealms.size() == 1) { logger.info("doSingleRealmAuthentication() execute "); return doSingleRealmAuthentication(typeRealms.iterator().next(), userToken); } else { logger.info("doMultiRealmAuthentication() execute "); return doMultiRealmAuthentication(typeRealms, userToken); } }}

  创建分别处理门店登录还是公司登录的Realm: 

import org.apache.shiro.authc.*;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.springframework.beans.factory.annotation.Autowired;import java.util.HashSet;import java.util.Set;/**公司登陆realm */public class MyShiroRealmCOMPANY extends AuthorizingRealm {    @Autowired    IUserService userService;    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {        String username = (String) principals.getPrimaryPrincipal(); // 一定是String类型,在SimpleAuthenticationInfo        SystemUser systemUser = userService.getUserByName(username, VirtualType.COMPANY);        if (systemUser == null) {            throw new RuntimeException("system concurrent exception: COMPANY user not found:username=" + username);        }        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();        Set
stringPermissions = new HashSet<>(256);      // 字符串资源 authorizationInfo.addStringPermissions(stringPermissions); return authorizationInfo; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {// UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; UserToken token = (UserToken)authenticationToken; // 逻辑登陆 return new SimpleAuthenticationInfo(token.getPrincipal(), token.getCredentials(), getName()); }}

  

import org.apache.shiro.authc.*;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.springframework.beans.factory.annotation.Autowired;import java.util.HashSet;import java.util.Set;/**门店登陆realm */public class MyShiroRealmSHOP extends AuthorizingRealm {    @Autowired    IUserService userService;    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {        String username = (String) principals.getPrimaryPrincipal(); // 一定是String类型,在SimpleAuthenticationInfo        SystemUser systemUser = userService.getUserByName(username, VirtualType.SHOP);        if (systemUser == null) {            throw new RuntimeException("system concurrent exception: SHOP user not found:username=" + username);        }        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();        Set
stringPermissions = new HashSet<>(256);     // 字符串资源 authorizationInfo.addStringPermissions(stringPermissions); return authorizationInfo; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {// UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; UserToken token = (UserToken)authenticationToken; // 逻辑登陆 return new SimpleAuthenticationInfo(token.getPrincipal(), token.getCredentials(), getName()); }}

  ShiroConfig配置

@Bean("securityManager")    public SecurityManager securityManager(RedisTemplate redisTemplate) {          // redisTemplate配置的redis缓存,可忽略        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();        List
realms = new ArrayList<>(); //添加多个Realm realms.add(myShiroRealmSHOP(redisTemplate)); realms.add(myShiroRealmCOMPANY(redisTemplate)); securityManager.setAuthenticator(modularRealmAuthenticator()); // 需要再realm定义之前 securityManager.setRealms(realms); securityManager.setSessionManager(myShiroSession(redisTemplate)); return securityManager; } /** * 系统自带的Realm管理,主要针对多realm 认证 */ @Bean public ModularRealmAuthenticator modularRealmAuthenticator() { //自己重写的ModularRealmAuthenticator UserModularRealmAuthenticator modularRealmAuthenticator = new UserModularRealmAuthenticator(); modularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy()); return modularRealmAuthenticator; } @Bean("myShiroRealmSHOP") public MyShiroRealmSHOP myShiroRealmSHOP(RedisTemplate redisTemplate) { return new MyShiroRealmSHOP(); } @Bean("myShiroRealmCOMPANY") public MyShiroRealmCOMPANY myShiroRealmCOMPANY(RedisTemplate redisTemplate) { return new MyShiroRealmCOMPANY(); }

  登陆即可:

subject.login(new UserToken(username, password, virtualType))  

 

这里需要注意的是,上述配置的Authenticator主要针对登陆认证,对于授权时没有控制的,使用资源注入时会发现,使用的是myShiroRealmSHOP的doGetAuthorizationInfo方法(上面SHOP的定义在前),没有走对应的realm的授权,产生问题错乱;

新建org.apache.shiro.authz.ModularRealmAuthorizer子类:

import org.apache.shiro.authz.Authorizer;import org.apache.shiro.authz.ModularRealmAuthorizer;import org.apache.shiro.realm.Realm;import org.apache.shiro.subject.PrincipalCollection; public class UserModularRealmAuthorizer extends ModularRealmAuthorizer {    @Override    public boolean isPermitted(PrincipalCollection principals, String permission) {        assertRealmsConfigured();        for (Realm realm : getRealms()) {            if (!(realm instanceof Authorizer)){ continue;}            //  todo 授权配置            if (realm.getName().contains(VirtualType.COMPANY.toString())) {    // 判断realm                if (permission.contains("company")) {    // 判断是否改realm的资源                    return ((MyShiroRealmCOMPANY) realm).isPermitted(principals, permission);    // 使用改realm的授权方法                }            }            if (realm.getName().contains(VirtualType.SHOP.toString())) {                if (permission.contains("shop")) {                    return ((MyShiroRealmSHOP) realm).isPermitted(principals, permission);                }            }        }        return false;    }}

  然后在ShiroConfig更改:

@Bean("securityManager")    public SecurityManager securityManager(RedisTemplate redisTemplate) {        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();        // 使用注解,@RequiresPermissions,读取缓存权限信息保存key对象为:{@link org.apache.shiro.subject.SimplePrincipalCollection},所以redis缓存配置的String不能转换//        securityManager.setCacheManager(redisCacheManager(redisTemplate));        List
realms = new ArrayList<>(); //添加多个Realm realms.add(myShiroRealmSHOP(redisTemplate)); realms.add(myShiroRealmCOMPANY(redisTemplate)); securityManager.setAuthenticator(modularRealmAuthenticator()); securityManager.setAuthorizer(modularRealmAuthorizer());    // 这里 securityManager.setRealms(realms); securityManager.setSessionManager(myShiroSession(redisTemplate)); return securityManager; } /** * 系统自带的Realm管理,主要针对多realm 认证 */ @Bean public ModularRealmAuthenticator modularRealmAuthenticator() { //自己重写的ModularRealmAuthenticator UserModularRealmAuthenticator modularRealmAuthenticator = new UserModularRealmAuthenticator(); modularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy()); return modularRealmAuthenticator; } /** * 系统自带的Realm管理,主要针对多realm 授权 */ @Bean public ModularRealmAuthorizer modularRealmAuthorizer() { //自己重写的ModularRealmAuthorizer UserModularRealmAuthorizer modularRealmAuthorizer = new UserModularRealmAuthorizer(); return modularRealmAuthorizer; } @Bean("myShiroRealmSHOP") public MyShiroRealmSHOP myShiroRealmSHOP(RedisTemplate redisTemplate) { return new MyShiroRealmSHOP(); } @Bean("myShiroRealmCOMPANY") public MyShiroRealmCOMPANY myShiroRealmCOMPANY(RedisTemplate redisTemplate) { return new MyShiroRealmCOMPANY(); }

  

参考:https://blog.csdn.net/cckevincyh/article/details/79629022 

转载于:https://www.cnblogs.com/skyLogin/p/10871347.html

你可能感兴趣的文章
小知识三、USerDefault我换个姿势来实现
查看>>
阿里架构师:程序员必须掌握的几项核心技术能力
查看>>
基于python的图片修复程序-可用于水印去除
查看>>
程序员常用的六大技术博客类
查看>>
Cell中添加Switch组件如何执行不同的函数
查看>>
浏览器兼容问题和webapp
查看>>
SQLAlchemy 最佳实践
查看>>
使用 Airflow 替代你的 crontab
查看>>
Runtime学习笔记整理
查看>>
表格中内容超出换行
查看>>
使用webpack打包koa2 app
查看>>
vue中动画的实现的几种方式
查看>>
Iceworks 2.8.0 发布,自定义你的 React 模板
查看>>
胖哥学SpringMVC:请求方式转换过滤器配置
查看>>
Kotlin 更加优雅的 Builder - 理解 with
查看>>
JVM 系列文章之 Full GC 和 Minor GC
查看>>
iOS Autolayout的一点小坑
查看>>
跨域资源共享CORS
查看>>
Java并发——信号量Semaphore
查看>>
swift 存放多类型的容器
查看>>