1. 程式人生 > >shiro報錯 org.apache.shiro.UnavailableSecurityManagerException

shiro報錯 org.apache.shiro.UnavailableSecurityManagerException

自己照著教程搭springboot+mybatis+shiro前後端分離的一個框架。碰到了問題,幾天了,很困惑,煩請知道的朋友給點建議

org.apache.shiro.UnavailableSecurityManagerException: No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton.  This is an invalid application configuration.

網上搜了兩圈答案無果。


執行這句話就報錯。getSubject();


shiroconfig的配置

package com.rdhl.dds.config;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.aspectj.lang.annotation.Before;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerExceptionResolver;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Created by Administrator on 2017/12/11.
 */
@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean shirFilter(@Qualifier("securityManager")SecurityManager securityManager) {
        System.out.println("ShiroConfiguration.shirFilter()-------------------------------");
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        //注意過濾器配置順序 不能顛倒
        //配置退出 過濾器,其中的具體的退出程式碼Shiro已經替我們實現了,登出後跳轉配置的loginUrl
        filterChainDefinitionMap.put("/logout", "logout");
//        // 配置不會被攔截的連結 順序判斷
        filterChainDefinitionMap.put("/druid/**", "anon");
        filterChainDefinitionMap.put("/static/**", "anon");
//        filterChainDefinitionMap.put("/ajaxLogin", "anon");
        filterChainDefinitionMap.put("/login", "anon");
//        filterChainDefinitionMap.put("/**", "authc");
        filterChainDefinitionMap.put("/**", "anon");
        //配置shiro預設登入介面地址,前後端分離中登入介面跳轉應由前端路由控制,後臺僅返回json資料
        shiroFilterFactoryBean.setLoginUrl("/unauth");
        // 登入成功後要跳轉的連結
//        shiroFilterFactoryBean.setSuccessUrl("/index");
        //未授權介面;
//        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    @Bean
    public SecurityManager securityManager(@Qualifier("myShiroRealm") MyShiroRealm myShiroRealm) {
        System.out.println("securityManager 執行----------------------");
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm);
        // 自定義session管理 使用redis
        securityManager.setSessionManager(sessionManager());
        // 自定義快取實現 使用redis
//        securityManager.setCacheManager(cacheManager());
        return securityManager;
    }

    /**
     * 憑證匹配器
     * (由於我們的密碼校驗交給Shiro的SimpleAuthenticationInfo進行處理了
     * )
     *
     * @return
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");//雜湊演算法:這裡使用MD5演算法;
        hashedCredentialsMatcher.setHashIterations(2);//雜湊的次數,比如雜湊兩次,相當於 md5(md5(""));
        return hashedCredentialsMatcher;
    }

    @Bean
    public MyShiroRealm myShiroRealm() {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
//        myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return myShiroRealm;
    }




    //自定義sessionManager
    @Bean
    public SessionManager sessionManager() {
        MySessionManager mySessionManager = new MySessionManager();
        mySessionManager.setSessionDAO(redisSessionDAO());
        return mySessionManager;
    }

    /**
     * 配置shiro redisManager
     * <p>
     * 使用的是shiro-redis開源外掛
     *
     * @return
     */
    @ConfigurationProperties(prefix = "redis.shiro")
    public RedisManager redisManager() {
        return new RedisManager();
    }

    /**
     * cacheManager 快取 redis實現
     * <p>
     * 使用的是shiro-redis開源外掛
     *
     * @return
     */
    @Bean
    public RedisCacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        return redisCacheManager;
    }

    /**
     * RedisSessionDAO shiro sessionDao層的實現 通過redis
     * <p>
     * 使用的是shiro-redis開源外掛
     */
    @Bean
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
//      Custom your redis key prefix for session management, if you doesn't define this parameter,
//      shiro-redis will use 'shiro_redis_session:' as default prefix
//      redisSessionDAO.setKeyPrefix("");
        return redisSessionDAO;
    }

    /**
     * 開啟shiro aop註解支援.
     * 使用代理方式;所以需要開啟程式碼支援;
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager")SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * 註冊全域性異常處理
     * @return
     */
    @Bean(name = "exceptionHandler")
    public HandlerExceptionResolver handlerExceptionResolver() {
        return new MyExceptionHandler();
    }
}

myshirorealm配置

package com.rdhl.dds.config;

import com.rdhl.dds.main.entity.Dictoper;
import com.rdhl.dds.system.entity.SRoleInfo;
import com.rdhl.dds.main.service.DictoperService;
import com.rdhl.dds.system.service.SRoleInfoService;
import org.apache.shiro.SecurityUtils;
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.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;

/**
 * Created by Administrator on 2017/12/11.
 * 自定義許可權匹配和賬號密碼匹配
 */
@Component(value="shiroRealm")
public class MyShiroRealm extends AuthorizingRealm {
    @Resource
    private SRoleInfoService sysRoleService;

    @Resource
    private DictoperService dictoperService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("doGetAuthorizationInfo-------------------------------");
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        Dictoper userInfo = (Dictoper) principals.getPrimaryPrincipal();
        try {
            List<SRoleInfo> roles = sysRoleService.findRoleById(userInfo.getRoleId());
            //給使用者加角色
            for (SRoleInfo role : roles) {
                authorizationInfo.addRole(role.getRoleName());
            }
            List<String> sysPermissions = dictoperService.getStringPermissionsByUser(userInfo.getOperid());
            authorizationInfo.addStringPermissions(sysPermissions);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return authorizationInfo;
    }

    /*主要是用來進行身份認證的,也就是說驗證使用者輸入的賬號和密碼是否正確。*/
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
            throws AuthenticationException {
        System.out.println("doGetAuthorizationInfo name ----------------------");
        //獲取使用者的輸入的賬號.
        String userName = (String) token.getPrincipal();//使用者名稱
        String password = new String((char[])token.getCredentials()); 	//得到密碼
        if(null != userName && null != password){
            return new SimpleAuthenticationInfo(userName, password, getName());
        }else{
            return null;
        }
    }

    /**
     * 將一些資料放到ShiroSession中,以便於其它地方使用
     * @see  比如Controller,使用時直接用HttpSession.getAttribute(key)就可以取到
     */
    private void setSession(Object key, Object value){
        Subject currentUser = SecurityUtils.getSubject();
        if(null != currentUser){
            Session session = currentUser.getSession();
            System.out.println("Session預設超時時間為[" + session.getTimeout() + "]毫秒");
            if(null != session){
                session.setAttribute(key, value);
            }
        }
    }

}

一隻穿雲箭,請求支援啊