shiro(15)-springboot2.x整合shiro(无状态认证)

shiro安全控制目录

前后端分离的架构中,采用的是Token的无状态认证模式。

token认证架构图.png

1. Maven依赖

        
        
            org.apache.shiro
            shiro-core
            1.2.3
        
        
            org.apache.shiro
            shiro-web
            1.2.3
        
        
            org.apache.shiro
            shiro-spring
            1.2.3
        

2. 配置

在普通的Spring项目中,Filter是由Servlet管理,需要我们在web.xml配置。但是在SpringBoot2.x中,所有的Servlet或者Filter 的Beans都会被servlet容器自动注册。

(1)shiro要配置一个servlet Filter,过滤所有的请求。

org.apache.shiro.spring.web.ShiroFilterFactoryBean是一个BeanFactory,实际返回bean为getObject()返回值,也就是org.apache.shiro.web.servlet.AbstractShiroFilter对象(Servlet Filter的子类)。

    @Bean(name="shiroFilterFactoryBean")
    public ShiroFilterFactoryBean shirFilter(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);     //设置安全管理器
        shiroFilterFactoryBean.setLoginUrl("/login");//     如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setSuccessUrl("/index"); //  登录成功后要跳转的链接
        shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");//未授权界面;
        Map filterMap = new HashMap();
            filterMap.put("/css/**","anon");
            filterMap.put("/layui/**","anon");
            filterMap.put("/img/**","anon");
            filterMap.put("/js/**","anon");
            filterMap.put("/html/**","anon");
            filterMap.put("/login/index","authc");
            filterMap.put("/login/login","anon");
            filterMap.put("/logout","logout");//配置退出 过滤器,其中的具体的退出代码Shiro已经实现
            filterMap.put("/**","authc");//过滤链定义,从上向下顺序执行,一般将/**放在最为下边
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        return shiroFilterFactoryBean ; 
        }

(2)shiro需要配置SecurityManager,协调管理所有组件。

shiro通过servlet Filter过滤所有的请求,但是如何去协调管理或自定义配置诸如(Realm、SessionManager、rememberMananger、CacheManager)组件,需要由SecurityMananger这位shiro大管家操心。

  1. SubjectContext在创建的时候,需要关闭session的创建,这个由DefaultWebSubjectFactorycreateSubject进行管理。
  2. 禁用Session作为存储的实现,这个主要由subjectDAOsessionStorageEvaluator进行管理。
  3. 禁用session调度器,主要用sessionManager进行管理。
    @Bean
    public SecurityManager securityManager(DefaultWebSubjectFactory jwtDefaultSubjectFactory, DefaultWebSessionManager sessionManager, DefaultSubjectDAO defaultSubjectDAO) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //配置Realm
        securityManager.setRealm(userAuthorizingRealm);
        //配置SubjectFactory,禁止创建Session
        securityManager.setSubjectFactory(jwtDefaultSubjectFactory);
        //配置sessionManager
        securityManager.setSessionManager(sessionManager);
        //配置SubjectDAO,subject禁止存储到session
        securityManager.setSubjectDAO(defaultSubjectDAO);
        return securityManager;
    }

    @Bean
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionIdCookieEnabled(false);
        sessionManager.setSessionValidationSchedulerEnabled(false);
        return sessionManager;
    }

    @Bean
    public DefaultSubjectDAO defaultSubjectDAO() {
        return new DefaultSubjectDAO() {
            @Override
            protected boolean isSessionStorageEnabled(Subject subject) {
                return false;
            }
        };
    }

    @Bean
    public DefaultWebSubjectFactory jwtDefaultSubjectFactory() {
        return new JwtDefaultSubjectFactory() {
            @Override
            public Subject createSubject(SubjectContext context) {
                // 不创建session
                context.setSessionCreationEnabled(false);
                Subject subject = super.createSubject(context);
                return subject;
            }
        };
    }

    @Bean
    public UserAuthorizingRealm userAuthorizingRealm(){
        UserAuthorizingRealm userAuthorizingRealm = new UserAuthorizingRealm();
        //暂时不使用缓存
        userAuthorizingRealm.setAuthorizationCachingEnabled(false);
        return userAuthorizingRealm;
    }

(3)自定义shiroFilter

在shiro中可以自定义过滤器链,对url进行精细化的控制。shiro Filter也是Servlet Filter的子类。使用@Bean将Shiro Filter Bean加入到容器时,Filter会自动注册到Servlet Filter Chain中,并且拦截路径默认为/。需要取消Filter的自动注册,手动的加入到Shiro Filter Chain中。

    //自定义权限过滤器
    @Bean
    public FilterRegistrationBean myPermissionFilterBean(MyPermissionFilter myPermissionFilter) {
        FilterRegistrationBean registration = new FilterRegistrationBean(myPermissionFilter);
        //取消自动注册
        registration.setEnabled(false);
        return registration;
    }

shiro(7)-shiroFilter(url上的权限控制)

也可以动态的配置过滤器链。

    @Bean("shiroFilterBean")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        shiroFilterFactoryBean.setFilterChainDefinitionMap(section);
        Map filterMap = new HashMap() {{
            put("authcFilter", myAuthcFilter);
            put("permissionFilter", myPermissionFilter);
        }};
        shiroFilterFactoryBean.setFilters(filterMap);
        return shiroFilterFactoryBean;
    }

    @Bean
    public ChainDefinitionSectionMetaSource section(){
        //FactoryBean
的子类,动态的拼装org.apache.shiro.config.Ini.Section类型。 return new ChainDefinitionSectionMetaSource(); }

ChainDefinitionSectionMetaSource 代码参考

(4)启动方法注解

在方法上可以使用注解来开启权限控制,实际上是AOP的实现之一

  /**
     * 开启aop注解支持
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(org.apache.shiro.mgt.SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

文章参考

Springboot与shiro整合遇到的坑

106.2 Spring Boot之Shiro无状态(2)【从零开始学Spring Boot】

spring boot 2.0 集成 shiro 和 pac4j cas单点登录

你可能感兴趣的:(shiro(15)-springboot2.x整合shiro(无状态认证))