Shiro 使用 JWT Token 配置类参考

项目中使用了 Shiro 进行验证和授权,下面是 Shiro 配置类给予参考。

后来并没有使用 Shiro,感觉使用 JWT 还是自己写拦截器比较灵活,使用 Shiro 后各种地方需要魔改,虽然功能也能实现,但感觉把简单问题复杂化了,如果单单只使用 Shiro 授权这一块可以尝试。

package com.nwgdk.ums.config.shiro;

import com.nwgdk.ums.config.shiro.filter.AccessTokenFilter;
import com.nwgdk.ums.config.shiro.listener.CustomSessionListener;
import com.nwgdk.ums.config.shiro.realm.AdminRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.mgt.DefaultWebSessionStorageEvaluator;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import javax.servlet.Filter;
import java.util.*;

/**
 * @author nwgdk
 */
@Configuration
@AutoConfigureAfter(ShiroLifecycleBeanPostProcessorConfiguartion.class)
public class ShiroConfiguration {

    /**
     * Hash迭代次数
     */
    @Value("${ums.config.hash.hash-iterations}")
    private Integer hashIterations;

    /**
     * WEB 过滤器链
     */
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager());
        // 注册自定义过滤器
        Map<String, Filter> filterMap = new LinkedHashMap<>(8);
        filterMap.put("authc", new AccessTokenFilter());
        shiroFilterFactoryBean.setFilters(filterMap);
        // 定义过滤链
        Map<String, String> filterChains = new LinkedHashMap<>(8);
        filterChains.put("/v1/admin/login", "anon");
        filterChains.put("/**", "authc");
        // 设置过滤器链
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChains);
        return shiroFilterFactoryBean;
    }

    /**
     * 安全管理器
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置 Session 管理器
        securityManager.setSessionManager(sessionManager());
        // 设置 Realm
        securityManager.setRealm(adminRealm());
        // 关闭 RememberMe
        securityManager.setRememberMeManager(null);
        // 设置自定义 Subject
        securityManager.setSubjectFactory(statelessDefaultSubjectFactory());
        // 设置 SubjectDao
        securityManager.setSubjectDAO(defaultSubjectDAO());
        return securityManager;
    }

    /**
     * 自定义 Subject 工厂, 禁止使用 Session
     */
    @Bean("subjectFactory")
    public StatelessDefaultSubjectFactory statelessDefaultSubjectFactory() {
        return new StatelessDefaultSubjectFactory();
    }

    @Bean
    public DefaultSubjectDAO defaultSubjectDAO() {
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        // 设置会话存储调度器
        subjectDAO.setSessionStorageEvaluator(defaultWebSessionStorageEvaluator());
        return subjectDAO;
    }

    /**
     * 会话存储器
     */
    @Bean
    public DefaultWebSessionStorageEvaluator defaultWebSessionStorageEvaluator() {
        DefaultWebSessionStorageEvaluator evaluator = new DefaultWebSessionStorageEvaluator();
        // 禁用会话存储
        evaluator.setSessionStorageEnabled(false);
        return evaluator;
    }

    /**
     * Session 管理器
     */
    @Bean
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        // 设置 Cookie
        sessionManager.setSessionIdCookie(simpleCookie());
        // 启用 Session Id Cookie,默认启用
        sessionManager.setSessionIdCookieEnabled(false);
        // 设置全局超时时间,默认30分钟
        sessionManager.setGlobalSessionTimeout(1800000L);
        // 设置会话监听器
        sessionManager.setSessionListeners(customSessionListener());
        // 禁用 Session 验证调度器
        sessionManager.setSessionValidationSchedulerEnabled(false);
        return sessionManager;
    }

    /**
     * 会话监听器
     */
    @Bean
    public Collection<SessionListener> customSessionListener() {
        List<SessionListener> listeners = new ArrayList<>();
        listeners.add(new CustomSessionListener());
        return listeners;
    }

    /**
     * Session Cookie
     */
    @Bean
    public SimpleCookie simpleCookie() {
        SimpleCookie cookie = new SimpleCookie();
        // Session Cookie 名称
        cookie.setName("SID");
        // Session 存活时间
        cookie.setMaxAge(10);
        // 设置 Cookie 只读
        cookie.setHttpOnly(true);
        return cookie;
    }

    /**
     * 凭证匹配器
     */
    @Bean("credentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        // 散列算法
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        // 散列次数
        hashedCredentialsMatcher.setHashIterations(hashIterations);
        // 使用 HEX 编码
        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
        return hashedCredentialsMatcher;
    }

    /**
     * 领域对象
     */
    @Bean("adminRealm")
    public AdminRealm adminRealm() {
        AdminRealm adminRealm = new AdminRealm();
        // 设置密码匹配器
        adminRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return adminRealm;
    }

    /**
     * 开启注解 (如 @RequiresRoles, @RequiresPermissions),
     * 需借助 SpringAOP 扫描使用 Shiro 注解的类,并在必要时进行安全逻辑验证
     * 配置以下两个 Bean:
     * DefaultAdvisorAutoProxyCreator(可选) 和 AuthorizationAttributeSourceAdvisor 即可实现此功能
     */
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }
}
package com.nwgdk.ums.config.shiro;

import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author nwgdk
 */
@Configuration
public class ShiroLifecycleBeanPostProcessorConfiguartion {

    /**
     * Shiro 生命周期处理器
     */
    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }
}
package com.nwgdk.ums.config.shiro;

import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.SubjectContext;
import org.apache.shiro.web.mgt.DefaultWebSubjectFactory;

/**
 * 自定义 Subject
 *
 * @author nwgdk
 */
public class StatelessDefaultSubjectFactory extends DefaultWebSubjectFactory {
    @Override
    public Subject createSubject(SubjectContext context) {
        // 禁止 Subject 创建会话
        context.setSessionCreationEnabled(false);
        return super.createSubject(context);
    }
}
posted @ 2019-07-01 19:47  NWGDK  阅读(2145)  评论(0编辑  收藏  举报