Spring Boot(十一)Shiro 整合 配置多 Realm

本文详细介绍如何在Shiro权限框架中实现自定义的多Realm验证模块,包括CustomizedModularRealmAuthenticator的创建,自定义Token的实现,以及ShiroRealmMini的定制。同时,展示了如何在ShiroConfig中配置这些自定义的Realm,实现灵活的权限控制。
import java.util.ArrayList;
import java.util.Collection;

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;

/**
 * CustomizedModularRealmAuthenticator
 * 多Realm验证模块
 */
public class CustomizedModularRealmAuthenticator extends ModularRealmAuthenticator {

    @Override
    protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken)
            throws AuthenticationException {
        // 判断getRealms()是否返回为空
        assertRealmsConfigured();
        // CustomizedToken
        CustomizedToken customizedToken = (CustomizedToken) authenticationToken;
        // 登录类型
        String loginType = customizedToken.getLoginType();
        // 所有Realm
        Collection<Realm> realms = getRealms();
        // 登录类型对应的所有Realm
        Collection<Realm> typeRealms = new ArrayList<>();
        for (Realm realm : realms) {
            //可以修改此规则来匹配你的登录类型
            if (realm.getName().contains(loginType)) {
                typeRealms.add(realm);
            }
        }
        if (typeRealms.size() == 1) {
            //单Realm
            return doSingleRealmAuthentication(typeRealms.iterator().next(), customizedToken);
        }
        else {
            //多Realm
            return doMultiRealmAuthentication(typeRealms, customizedToken);
        }
    }
}
import org.apache.shiro.authc.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;
    }
}
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hwx.api.entity.StoreUser;
import com.hwx.api.entity.SysUser;
import com.hwx.api.service.IMiniappConfigService;
import com.hwx.api.service.IStoreUserService;
import com.hwx.util.Const;
import com.hwx.util.Jurisdiction;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import javax.annotation.Resource;

public class ShiroRealmMini extends AuthorizingRealm {
    @Resource
    IStoreUserService iStoreUserService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //获取用户的输入的账号.
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        String username = usernamePasswordToken.getUsername();
        String password = String.valueOf(usernamePasswordToken.getPassword());

        //根据用户名查询,用户名必须是唯一
        QueryWrapper<StoreUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("openId", username);
        StoreUser storeUser = iStoreUserService.getOne(queryWrapper);

        /*校验密码*/
        /*加密方式*/
        String algorithmName = "MD5";
        /*加密次数*/
        int hashIterations = 2000;
        /*加密盐值 username作为颜值必须为唯一值 注册时需要注意*/
        Object salt = ByteSource.Util.bytes(storeUser.getUnionId());
        /*md5Result:9ec808d39c36c800591f1ee14f5f3175*/
        String md5Result = new SimpleHash("MD5", password, salt, hashIterations).toHex();
        /*判断用户密码是否正确,状态等*/
        if (storeUser != null) {
            if (md5Result.equals(storeUser.getPassword())) {
                /*session用户*/
                Session session = Jurisdiction.getSession();
                session.setAttribute(username + Const.SESSION_USER,storeUser);
                /*通过身份验证*/
                /*principal:认证信息,可以是username,也可以是整个实体*/
                Object principal = storeUser;
                /*credentials:密码*/
                Object credentials = storeUser.getPassword();
                /*credentialsSalt:盐值*/
                ByteSource credentialsSalt = ByteSource.Util.bytes(storeUser.getUnionId());
                /*realmName:当前realm对象的name,调用父类getName()*/
                String realmName = getName();

                SimpleAuthenticationInfo simpleAuthorizationInfo  = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);
                return simpleAuthorizationInfo;
            }
        }
        return null;
    }
}

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import java.util.*;

@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        System.out.println("ShiroConfiguration.shirFilter()");
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        /*拦截器*/
        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
        /*配置不会被拦截的链接 顺序判断*/
        /*anon:所有url都都可以匿名访问*/
        /*webjars swagger 加载到webjar的资源,所以webjar下的资源不能被拦截,否者无法访问*/
        filterChainDefinitionMap.put("/webjars/**", "anon");
        filterChainDefinitionMap.put("/swagger-ui.html", "anon");
        filterChainDefinitionMap.put("/swagger-resources/**", "anon");
        filterChainDefinitionMap.put("/v2/api-docs/**", "anon");
        filterChainDefinitionMap.put("/app/**", "anon");
        filterChainDefinitionMap.put("/D://uploadfile/**", "anon");

        /*配置退出*/
        filterChainDefinitionMap.put("/logout", "logout");
        filterChainDefinitionMap.put("/api/user/login", "anon");
        filterChainDefinitionMap.put("/api/user/minilogin", "anon");
        filterChainDefinitionMap.put("/api/file/fileUpload", "anon");
        filterChainDefinitionMap.put("/index", "anon");
        /*过滤链定义,从上向下顺序执行,一般将/**放在最为下*/
        /*authc:所有url都必须认证通过才可以访问-->*/
        filterChainDefinitionMap.put("/**", "authc");
        /*如果不设置默认会自动寻找Web工程根目录下的"/login"页面*/
        shiroFilterFactoryBean.setLoginUrl("/app/admin/index.html");
        /* 登录成功后要跳转的链接*/
        shiroFilterFactoryBean.setSuccessUrl("/userInfo");
        /*未授权界面*/
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return shiroFilterFactoryBean;
    }

    /**
     * 系统自带的Realm管理,主要针对多realm
     * */
    @Bean
    public ModularRealmAuthenticator modularRealmAuthenticator(){
        //自己重写的ModularRealmAuthenticator
        CustomizedModularRealmAuthenticator customizedModularRealmAuthenticator = new CustomizedModularRealmAuthenticator();
        customizedModularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
        return customizedModularRealmAuthenticator;
    }

    /**
     * 凭证匹配器(由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了)
     * @return
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");   //散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(2000);       //散列的次数,比如散列两次,相当于 md5(md5(""));
        return hashedCredentialsMatcher;
    }

    @Bean
    public ShiroRealmPC ShiroRealmPC(){
        ShiroRealmPC shiroRealmPC = new ShiroRealmPC();
        shiroRealmPC.setCredentialsMatcher(hashedCredentialsMatcher());
        return shiroRealmPC;
    }

    @Bean
    public ShiroRealmMini ShiroRealmMini(){
        ShiroRealmMini shiroRealmMini = new ShiroRealmMini();
        shiroRealmMini.setCredentialsMatcher(hashedCredentialsMatcher());//设置解密规则
        return shiroRealmMini;
    }

    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        securityManager.setAuthenticator(modularRealmAuthenticator());
        List<Realm> realms = new ArrayList<>();
        //添加多个Realm
        realms.add(ShiroRealmPC());
        realms.add(ShiroRealmMini());
        securityManager.setRealms(realms);
        // 自定义缓存实现 使用redis
        //securityManager.setCacheManager(cacheManager());
        // 自定义session管理 使用redis
        //securityManager.setSessionManager(sessionManager());
        //注入记住我管理器;
        //securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }

    /**
     *  开启shiro aop注解支持.
     *  使用代理方式;所以需要开启代码支持;
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean(name="simpleMappingExceptionResolver")
    public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() {
        SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();
        Properties mappings = new Properties();
        mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理
        mappings.setProperty("UnauthorizedException","403");
        r.setExceptionMappings(mappings);               // None by default
        r.setDefaultErrorView("error");                 // No default
        r.setExceptionAttribute("ex");                  // Default is "exception"
        r.setWarnLogCategory("example.MvcLogger");      // No default
        return r;
    }
}
  1. 自定义CustomizedModularRealmAuthenticator 并继承 ModularRealmAuthenticator
  2. 自定义CustomizedToken 并继承 UsernamePasswordToken
  3. 自定义ShiroRealmMini ,可以写很多很多个这样的Realm
  4. ShiroConfig 中配置 ShiroRealmMini等Realm
  5. 然后就可以了
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

神奇的网友

day day up

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值