shiro配置 在springboot中前后端分离中,集成shiro认证授权框架

本文介绍Apache Shiro权限管理系统,包括其认证与授权机制,并详细展示了如何在Spring Boot应用中进行Shiro配置,涵盖属性配置、自定义过滤器及Realm实现等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一:介绍

    Apache Shiro是Java的一个安全框架。由于它相对小而简单,现在使用的人越来越多。

    Authentication:身份认证/登录,验证用户是不是拥有相应的身份。

    Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限。

二:配置

   springboot application-dev.yml 配置文件

spring:   
  shiro:
    properties:
      authz: false
    session-id-cookie:
      http-only: false
      name: yui2-token
      maxAge: 2592000
    session-dao:
      #expire: 86400 选用globalSessionTimeout这个值
      session-prefix: yui2-sid
    session-mgr:
      globalSessionTimeout: 86400000
    shiro-db-realm:
      authentication-caching-enabled: false
      authorization-caching-enabled: false
      authentication-cache-name: yui2-cache-authc
      authorization-cache-name: yui2-cache-authz

authz:false,表示是否开启后端授权
session-id-cookie.http-only:false,如果为true,浏览器读取不到这个token。
session-id-cookie.name:yui2-token,这个值cookie的名称。
session-id-cookie.maxAge:2592000,这个cookie在浏览器保留时间。
session-dao.session-prefix: sessionId,前缀。
session-mgr.globalSessionTimeout:session过期时间。
shiro-db-realm.authentication-caching-enabled: false。表示是否开启用户信息缓存
shiro-db-realm.authorization-caching-enabled: false。 表示是否开启权限信息缓存
shiro-db-realm.authentication-cache-name: yui2-cache-authc。 表示用户信息缓存名称
shiro-db-realm. authorization-cache-name: yui2-cache-authz。 表示权限信息缓存名称


springboot配置文件,ShiroConfig.java

@Configuration
public class ShiroConfig {
    private static final Logger logger = LoggerFactory.getLogger(ShiroConfig.class);
    
    @Bean("ShiroProperties")
    @ConfigurationProperties("spring.shiro.properties")
    public ShiroProperties shiroProperties(){
        return new ShiroProperties();
    }
    
    @Bean("shiroFilter")
    //@ConfigurationProperties("spring.shiro.shiro-filter")
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager, ShiroProperties shiroProperties) throws IOException {
        logger.info("ShiroConfiguration.shirFilter()");
        
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //shiroFilterFactoryBean.setLoginUrl("/view/login.html");
        //shiroFilterFactoryBean.setSuccessUrl("/view/index.html");
        //shiroFilterFactoryBean.setUnauthorizedUrl("/view/error/403.html");
        
        //定义过滤器
        Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
        filters.put("fLogin", new ForceLogoutFilter());
        filters.put("mauthc", new WebAndAppFormAuthenticationFilter());
        filters.put("mperms", new FramePermissionsAuthorizationFilter(shiroProperties.isAuthz()));
        
        shiroFilterFactoryBean.setFilters(filters);
        
        //拦截器.
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
//        //静态文件
//        filterChainDefinitionMap.put("/assets/**", "anon");
//        filterChainDefinitionMap.put("/css/**", "anon");
//        filterChainDefinitionMap.put("/fonts/**", "anon");
//        filterChainDefinitionMap.put("/img/**", "anon");
//        filterChainDefinitionMap.put("/js/**", "anon");
//        filterChainDefinitionMap.put("/sampledata/**", "anon");
//        
//        //view页面
//        filterChainDefinitionMap.put("/view/login", "anon");
//        filterChainDefinitionMap.put("/view/login.html", "anon");
//        
//        //controller 访问
//        filterChainDefinitionMap.put("/access/**", "anon");
//        filterChainDefinitionMap.put("/logout", "logout");
//        
//        filterChainDefinitionMap.put("/**", "fLogin, mauthc, mperms");
        //通过加载properties文件实现
        OrderedPropertiesReader opReader = OrderedPropertiesReader.getInstance(); 
        Map<String, String> propertyMap = opReader.getPropertyMap("shiroFilterChainDefinition.properties");
        filterChainDefinitionMap.putAll(propertyMap);
        
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }
    
    /**
     * 会话Cookie模板
     */
    @Bean("sessionIdCookie")
    @ConfigurationProperties("spring.shiro.session-id-cookie")
    public Cookie sessionIdCookie(){
        return new SimpleCookie("yui2-token");//默认为yui2-token
    }
    
    /**
     * 会话ID生成器
     */
    @Bean("sessionIdGenerator")
    public SessionIdGenerator sessionIdGenerator(){
        return new JavaUuidSessionIdGenerator();
    }
    
    /**
     * Redis 实现 ShiroSessionDao
     */
    @Bean("sessionDAO")
    @ConfigurationProperties("spring.shiro.session-dao")
    public SessionDAO sessionDAO(RedisRepository redisRepository, SessionIdGenerator sessionIdGenerator){
        RedisShiroSessionDao redisShiroSessionDao = new RedisShiroSessionDao();
        redisShiroSessionDao.setRedisRepository(redisRepository);
        redisShiroSessionDao.setSessionIdGenerator(sessionIdGenerator);
        return redisShiroSessionDao;
    }
    
    @Bean("cacheManager")
    public CacheManager cacheManager(RedisRepository redisRepository){
        ShiroRedisCacheManager cacheManager = new ShiroRedisCacheManager();
        cacheManager.setRedisRepository(redisRepository);
        return cacheManager;
    }
    
    @Bean("sessionManager")
    @ConfigurationProperties("spring.shiro.session-mgr")
    public SessionManager sessionManager(SessionDAO sessionDAO, Cookie sessionIdCookie){
        WebAndAppSessionManager sessionManager = new WebAndAppSessionManager();
        sessionManager.setSessionValidationSchedulerEnabled(false);
        sessionManager.setSessionDAO(sessionDAO);
        sessionManager.setSessionIdCookie(sessionIdCookie);
        return sessionManager;
    }
    
    @Bean("subjectFactory")
    public SubjectFactory subjectFactory(){
        return new DefaultWebSubjectFactory();
    }
    
    @Bean("securityManager")
    public SecurityManager securityManager(SessionManager sessionManager, Realm shiroDBRealm, 
            SubjectFactory subjectFactory, CacheManager cacheManager){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setSessionManager(sessionManager);
        securityManager.setRealm(shiroDBRealm);
        securityManager.setSubjectFactory(subjectFactory);
        securityManager.setCacheManager(cacheManager);
        return securityManager;
    }
    
    @Bean("shiroDBRealm")
    @ConfigurationProperties("spring.shiro.shiro-db-realm")
    public Realm shiroDBRealm(){
        ShiroDBRealm shiroDBRealm = new ShiroDBRealm();
        shiroDBRealm.setAuthenticationCacheName("authenticationCache");
        shiroDBRealm.setAuthorizationCacheName("authorizationCache");
        return shiroDBRealm;
    }
    
    @Bean("lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }
    
    @Bean("methodInvokingFactoryBean")
    public MethodInvokingFactoryBean methodInvokingFactoryBean(SecurityManager securityManager) {
        MethodInvokingFactoryBean factoryBean = new MethodInvokingFactoryBean();
        factoryBean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
        factoryBean.setArguments(new Object[]{securityManager});
        return factoryBean;
    }
    
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
        proxyCreator.setProxyTargetClass(true);
        return proxyCreator;
    }
    
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }
    
  

    
}

Shiro 用户信息和授权信息,缓存配置,这里使用了redis缓存

import java.util.Collection;
import java.util.Set;

import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import yui.comn.redis.RedisRepository;
import yui.comn.utils.SerializeUtils;

/**
 * Redis 实现Shiro缓存
 * @author yuyi   1060771195@qq.com
 */
public class ShiroRedisCache<K, V> implements Cache<K, V> {
    public static Logger logger = LoggerFactory.getLogger(ShiroRedisCache.class);
    
    private String  name;
    private RedisRepository redisRepository;
    
    public ShiroRedisCache(String name, RedisRepository redisRepository) {
        this.name = name;
        this.redisRepository = redisRepository;
    }
    
    private byte[] getByteKey(K key) {
        if (key instanceof String) {
            String preKey = key.toString();
            return preKey.getBytes();
        } else {
            return SerializeUtils.serialize(key);
        }
    }
    
    private byte[] getByteName() {
        return name.getBytes();
    }
    
    @Override
    public void clear() throws CacheException {
        logger.debug("从redis中删除所有元素");
        try {
            redisRepository.del(getByteName());
        } catch (Throwable t) {
            throw new CacheException(t);
        }
        
    }

    @SuppressWarnings("unchecked")
    @Override
    public V get(K key) throws CacheException {
        logger.debug("根据key从Redis中获取对象 key [" + key + "]");
        try {
            if (key == null) {
                return null;
            } else {
                V value = (V) redisRepository.hGet(getByteName(), getByteKey(key));
                return value;
            }
        } catch (Throwable t) {
            throw new CacheException(t);
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public Set<K> keys() {
        try {
            Set<K> keys = redisRepository.hKeys(getByteName());
            return keys;
        } catch (Throwable t) {
            throw new CacheException(t);
        }
    }

    @Override
    public V put(K key, V val) throws CacheException {
        logger.debug("根据key从存储 key [" + key + "]");
        try {
            redisRepository.hPut(getByteName(), getByteKey(key), SerializeUtils.serialize(val));
            return val;
        } catch (Throwable t) {
            throw new CacheException(t);
        }
    }

    @Override
    public V remove(K key) throws CacheException {
        logger.debug("从redis中删除 key [" + key + "]");
        try {
            V previous = get(key);
            redisRepository.hDel(getByteName(), getByteKey(key));
            return previous;
        } catch (Throwable t) {
            throw new CacheException(t);
        }
    }

    @Override
    public int size() {
        try {
            Long longSize = new Long(redisRepository.hLen(getByteName()));
            return longSize.intValue();
        } catch (Throwable t) {
            throw new CacheException(t);
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public Collection<V> values() {
        try {
            Collection<V> values = redisRepository.hVals(getByteName());
            return values;
        } catch (Throwable t) {
            throw new CacheException(t);
        }
    }

    
}
import org.apache.shiro.cache.AbstractCacheManager;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;

import yui.comn.redis.RedisRepository;

/**
 * redis 缓存管理器
 * @author yuyi  1060771195@qq.com
 */
public class ShiroRedisCacheManager extends AbstractCacheManager {

    private RedisRepository redisRepository;
    
    @Override
    protected Cache<String, Object> createCache(String cacheName) throws CacheException {
        return new ShiroRedisCache<String, Object>(cacheName, redisRepository);
    }

    public RedisRepository getRedisRepository() {
        return redisRepository;
    }

    public void setRedisRepository(RedisRepository redisRepository) {
        this.redisRepository = redisRepository;
    }
}

Shiro 基于redis存储的SessionDao

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SimpleSession;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import yui.comn.redis.RedisRepository;
import yui.comn.utils.DateUtils;

/**
 * Redis实现的 ShiroSessionDao
 * @author yuyi  1060771195@qq.com
 */
public class RedisShiroSessionDao extends AbstractSessionDAO {
    public Logger logger = LoggerFactory.getLogger(RedisShiroSessionDao.class);
    
    private String sessionPrefix = "yui2-sid";
    private Long expire = 28800L; //28800L;
    private RedisRepository redisRepository;
    
    @Override
    public void update(Session session) throws UnknownSessionException {
        try {
            SimpleSession simpleSession = (SimpleSession) session;
            simpleSession.setStartTimestamp(DateUtils.currentTimestamp());
            
            long expireSec = null != expire ? expire : session.getTimeout()/1000;
            redisRepository.put(getTbSid(session), session, expireSec);
        } catch (Exception e) {
            logger.error("更新session失败", e);
        }

    }

    @Override
    public void delete(Session session) {
        try {
            redisRepository.del(getTbSid(session));
        } catch (Exception e) {
            logger.error("删除session失败", e);
        }
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Override
    public Collection<Session> getActiveSessions() {
        String pattern = getTbSid(sessionPrefix + "-*");
        List list = null;
        try {
            Set keys = redisRepository.keys(pattern);
            if (null != keys) {
                list =  new ArrayList<Object>(keys);
            }
        } catch (Exception e) {
            logger.error("获取有效session失败", e);
        }
        return list;
    }

    @Override
    protected Serializable doCreate(Session session) {
        Serializable sessionId = session.getId();
        try {
            super.assignSessionId(session, sessionPrefix + "-" + super.generateSessionId(session));
            update(session);
            sessionId = session.getId();
        } catch (Exception e) {
            logger.error("创建session失败", e);
        }
        return sessionId;
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
        Session session = null;
        try {
            session = (Session) redisRepository.get(getTbSid(sessionId));
        } catch (Exception e) {
            logger.error("读取session失败", e);
        }
        return session;
    }

    public String getTbSid(Session session) {
        if (null == session.getId()) {
            return null;
        }
        return getTbSid(session.getId());
    }
    
    public String getTbSid(String sid) {
        return new StringBuffer(sessionPrefix).append(":").append(sid).toString();
    }
    
    public String getTbSid(Serializable sid) {
        return getTbSid(sid.toString());
    }
    
    
    
    
    public void setSessionPrefix(String sessionPrefix) {
        this.sessionPrefix = sessionPrefix;
    }

    public void setExpire(Long expire) {
        this.expire = expire;
    }

    public void setRedisRepository(RedisRepository redisRepository) {
        this.redisRepository = redisRepository;
    }
}

Shiro  自己覆写实现类,WebAndAppSessionManager继承DefaultWebSessionManager,如果header带有token信息,先从header中获取token信息。

如果header没有带有token信息,再去shiro默认实现中去获取。

Shiro默认先去cookie中去获取,如果cookie中没有token,再去参数中去获取是否带有token参数信息。

import java.io.Serializable;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;

/**
 * @author yuyi  1060771195@qq.com
 */
public class WebAndAppSessionManager extends DefaultWebSessionManager {

    @Override
    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
        Cookie sessionIdCookie = getSessionIdCookie();
        HttpServletRequest httpReq = (HttpServletRequest) request;
        String shiroToken = httpReq.getHeader(sessionIdCookie.getName());
        if (null != shiroToken) {
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
                    ShiroHttpServletRequest.URL_SESSION_ID_SOURCE);
            return shiroToken;
        }
        return super.getSessionId(request, response);
    }   
    
}

Shiro 实现ShiroDBRealm类,实现认证和授权方法,和清除缓存方法。

import java.util.Collection;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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.SimplePrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;

import yui.comn.shiro.mgr.IUserDetailMgrx;
import yui.comn.shiro.utils.ShiroConstant;
import yui.comn.utils.SpringContextUtils;
import yui.comn.utils.UserInfo;

/**
 * @author yuyi  1060771195@qq.com
 */
//@Service
public class ShiroDBRealm extends AuthorizingRealm {

    private IUserDetailMgrx userDetailMgrx;
    
    private IUserDetailMgrx getUserDetailMgrx() {
        //解决shiro不能注入dubbo的bug
        if (null == userDetailMgrx) {
            userDetailMgrx = (IUserDetailMgrx) SpringContextUtils.getBean(IUserDetailMgrx.USER_DETAIL_MGRX);
        }
        return userDetailMgrx;
    }
    
    public void setUserDetailMgrx(IUserDetailMgrx userDetailMgrx) {
        this.userDetailMgrx = userDetailMgrx;
    }
    
    /**
     * 认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
            throws AuthenticationException {
        
        String principal = token.getPrincipal().toString();
        
        //forceLogoutBefore(principal);
        
        UserInfo userInfo = getUserDetailMgrx().getUserInfo(principal);
        
        PrincipalCollection principalCollection = new SimplePrincipalCollection(userInfo, ShiroConstant.AUTHORIZING_REALM_NAME);
        return new SimpleAuthenticationInfo(principalCollection, token.getCredentials());
    }
    
    /**
     * 强制退出之前的账号
     * @param username
     */
    @SuppressWarnings("unused")
    private void forceLogoutBefore(String username) {
        DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
        DefaultWebSessionManager sessionManager = (DefaultWebSessionManager) securityManager.getSessionManager();
        Collection<Session> activeSessions = sessionManager.getSessionDAO().getActiveSessions();
        for (Session session : activeSessions) {
            SimplePrincipalCollection principals = (SimplePrincipalCollection) session.getAttribute(
                    DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
            UserInfo userInfo = (UserInfo) principals.getPrimaryPrincipal();
            if (StringUtils.equalsIgnoreCase(userInfo.getUsername(), username)) {
                if (null == session.getAttribute(ShiroConstant.SESSION_FORCE_LOGOUT_KEY)) {
                    session.setAttribute(ShiroConstant.SESSION_FORCE_LOGOUT_KEY, Boolean.TRUE); 
                    sessionManager.getSessionDAO().update(session);
                }
            }
        }
    }
    
    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        UserInfo userInfo = (UserInfo) principals.getPrimaryPrincipal();  //从这里可以从cas server获得认证通过的用户名,得到后我们可以根据用户名进行具体的授权
        
        Map<String, Set<String>> roleAndPermMap = getUserDetailMgrx().getRoleAndPerm(userInfo.getSysUserPk());
        
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();  
        authorizationInfo.setRoles(roleAndPermMap.get(IUserDetailMgrx.ROLE_MAP_KEY));
        authorizationInfo.setStringPermissions(roleAndPermMap.get(IUserDetailMgrx.PERM_MAP_KEY));
        
        return authorizationInfo;
    }
    
    @Override
    public AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {
        return super.getAuthorizationInfo(principals);
    }
    
    /**
     * 覆写认证缓存key
     */
    @Override
    protected Object getAuthenticationCacheKey(PrincipalCollection principals) {
        UserInfo userInfo = (UserInfo) principals.getPrimaryPrincipal();
        return userInfo.getUsername();
        //return super.getAuthenticationCacheKey(principals);
    }
    
    /**
     * 覆写授权缓存key
     */
    @Override
    protected Object getAuthorizationCacheKey(PrincipalCollection principals) {
        UserInfo userInfo = (UserInfo) principals.getPrimaryPrincipal();
        return userInfo.getUsername();
        //return super.getAuthenticationCacheKey(principals);
    }

    @Override
    public void clearCache(PrincipalCollection principals) {
        super.clearCache(principals);
    }
    
    /**
     * 通过用户名清除缓存
     */
    public void clearCache(String username) {
        PrincipalCollection principals = new SimplePrincipalCollection(
                new UserInfo(username), ShiroConstant.AUTHORIZING_REALM_NAME);
        clearCache(principals);
    }
    
    /**
     * 清除认证和授权缓存
     */
    public void clearAllCache() {
        clearAllAuthcCache();
        clearAllAuthzCache();
    }
    
    /**
     * 清除认证缓存
     */
    public void clearAllAuthcCache() {
        getAuthenticationCache().clear();
    }
    
    /**
     * 清除授权缓存
     */
    public void clearAllAuthzCache() {
        getAuthorizationCache().clear();
    }
    
    
}
/**
 * @author yuyi  1060771195@qq.com
 */
public class ShiroConstant {

    //realm名称
    public static final String AUTHORIZING_REALM_NAME="shiroDbAuthorizingRealmName";
    //强制退出标识
    public static final String SESSION_FORCE_LOGOUT_KEY = "sessionForceLogoutKey";
    
}

Shiro  自己覆写实现类,自定义过滤去,WebAndAppFormAuthenticationFilter继承FormAuthenticationFilter,实现异步返回json数据结果,对于前后端分离,全部请求都返回json。

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Web And App FormAuthenticationFilter
 * @author yuyi  1060771195@qq.com
 */
public class WebAndAppFormAuthenticationFilter extends FormAuthenticationFilter {

private static final Logger logger = LoggerFactory.getLogger(WebAndAppFormAuthenticationFilter.class);
    
    private String noAuthenticationReturn = "{\"status\": \"401\", \"message\":\"未授权的访问,请检查Token后重试\"}";
    
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response)
            throws Exception {
        if (isLoginRequest(request, response)) {
            if (isLoginSubmission(request, response)) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Login submission detected.  Attempting to execute login.");
                }
                return executeLogin(request, response);
            } else {
                if (logger.isTraceEnabled()) {
                    logger.trace("Login page view.");
                }
                //allow them to see the login page ;)
                return true;
            }
        } else {
            if (logger.isTraceEnabled()) {
                logger.trace("Attempting to access a path which requires authentication.  Forwarding to the " +
                        "Authentication url [" + getLoginUrl() + "]");
            }
            response.setContentType("text/html;charset=UTF-8");
            
          //如果header带有token信息
            String refSessionIdSource = (String) request.getAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE);
            if (ShiroHttpServletRequest.URL_SESSION_ID_SOURCE.equals(refSessionIdSource)) {
                response.getWriter().write(noAuthenticationReturn);
            } else {
                //如果ajax异步请求
                HttpServletRequest httpRequest = (HttpServletRequest) request;
                String reqtType = httpRequest.getHeader("X-Requested-With");
                if (null != reqtType) {
                    response.getWriter().write(noAuthenticationReturn);
                } else {
                    //因为都是异步请求
                    response.getWriter().write(noAuthenticationReturn);
                    //saveRequestAndRedirectToLogin(request, response);
                }
            }
            return false;
        }
    }
    
    public void setNoAuthenticationReturn(String noAuthenticationReturn) {
        this.noAuthenticationReturn = noAuthenticationReturn;
    }
}

Shiro  自己覆写实现类,自定义过滤去,ForceLogoutFilter继承AccessControlFilter,如果有用户被强制退出,该用户再次访问时会返回"{\"status\": \"402\", \"msg\":\"被强制退出\"}",表示用户被强制退出,去要再次登陆。

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.session.Session;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import yui.comn.shiro.utils.ShiroConstant;

/**
 * 强制退出
 * @author yuyi  1060771195@qq.com
 */
public class ForceLogoutFilter extends AccessControlFilter {

private static final Logger logger = LoggerFactory.getLogger(ForceLogoutFilter.class);
    @SuppressWarnings("unused")
    private String redirectUrl; //= "http://127.0.0.1:8080/cas/logout?service=http://127.0.0.1:8181/adm/";
    private String forceLogoutReturn = "{\"status\": \"402\", \"msg\":\"被强制退出\"}";
    
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response,
            Object mappedValue) throws Exception {
        
        Session session = getSubject(request, response).getSession(false);  
        if(null == session) { 
            return true;  
        }
        return null == session.getAttribute(ShiroConstant.SESSION_FORCE_LOGOUT_KEY);  
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response)
            throws Exception {
        if (logger.isTraceEnabled()) {
            logger.trace("Attempting to access a path which force logout.  Forwarding to the " +
                    "Authentication url [" + getLoginUrl() + "]");
        }
        
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        
        String refSessionIdSource = (String) request.getAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE);
        if (ShiroHttpServletRequest.URL_SESSION_ID_SOURCE.equals(refSessionIdSource)) {
            logout(request, response);
            response.getWriter().write(forceLogoutReturn);
        } else {
            String reqtType = httpRequest.getHeader("X-Requested-With");
            if (null != reqtType) {
                response.getWriter().write(forceLogoutReturn);
            } else {
                logout(request, response);
                saveRequest(request);
                //WebUtils.issueRedirect(request, response, redirectUrl);
                saveRequestAndRedirectToLogin(request, response);
            }
        }
        return false;  
    }
    
    //删除session
    private void logout(ServletRequest request, ServletResponse response) throws ServletException, IOException {
        //Exception exception = null;
        try {  
            getSubject(request, response).logout();//强制退出  
        } catch (Exception e) {
            logger.error("强制退出失败", e);
        } finally {
            //cleanup(request, response, exception);
        }
    }

    public void setRedirectUrl(String redirectUrl) {
        this.redirectUrl = redirectUrl;
    }
    public void setForceLogoutReturn(String forceLogoutReturn) {
        this.forceLogoutReturn = forceLogoutReturn;
    }

}

Shiro  自己覆写实现类,自定义过滤去,FramePermissionsAuthorizationFilter继承PermissionsAuthorizationFilter,进行授权过滤,默认不开启,如果开启会对每个接口进行授权。

import java.io.IOException;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author yuyi  1060771195@qq.com
 */
public class FramePermissionsAuthorizationFilter extends PermissionsAuthorizationFilter {
    private static Logger logger = LoggerFactory.getLogger(FramePermissionsAuthorizationFilter.class);
    
    private boolean isAuthz;
    
    public FramePermissionsAuthorizationFilter() {
        super();
    }
    
    public FramePermissionsAuthorizationFilter(boolean isAuthz) {
        super();
        this.isAuthz = isAuthz;
    }

    @Override
    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
        
        if (!isAuthz) {
            return true;
        }
        
        HttpServletRequest req = (HttpServletRequest) request;
        Subject subject = getSubject(request, response);
        
        String uri = req.getRequestURI();
        String contextPath = req.getContextPath();
        
        int index = uri.indexOf(contextPath);
        if(index > -1){
            uri = uri.substring(index + contextPath.length());
        }
        
        //首页免登录
        if (StringUtils.equals("/", uri)) {
            return true;
        }
        //阿里druid数据源默认全部允许
        if (StringUtils.indexOf(uri, "/druid") == 0) {
            return true;
        }
        //如果不是菜单,变成shiro资源格式
        if (!StringUtils.contains(uri, ".")) {
            uri = StringUtils.substring(uri, 1);
            uri = StringUtils.replace(uri, "/", ":");
        }
        
        boolean permitted = subject.isPermitted(uri);
        
        if (!permitted) {
            logger.warn("uri[" + uri + "] is no perm");
        }
        
        return permitted;
    }

    public boolean isAuthz() {
        return isAuthz;
    }

    public void setAuthz(boolean isAuthz) {
        this.isAuthz = isAuthz;
    }
}

序列化类SerializeUtils :

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SerializeUtils {
    public static Logger logger = LoggerFactory.getLogger(SerializeUtils.class);
    
	public static byte[] serialize(Object object) {
	    if(null == object){
            return null;
        }
		
		ObjectOutputStream oos = null;
		ByteArrayOutputStream baos = null;
		try {
			// 序列化
			baos = new ByteArrayOutputStream();
			oos = new ObjectOutputStream(baos);
			oos.writeObject(object);
			byte[] bytes = baos.toByteArray();
			return bytes;
		} catch (Exception e) {
		    logger.error("序列化失败", e);
		}
		
		return null;
	}

	public static Object deserialize(byte[] bytes) {
	    if(null == bytes){
            return null;
        }
	    
		ByteArrayInputStream bais = null;
		try {
			// 反序列化
			bais = new ByteArrayInputStream(bytes);
			ObjectInputStream ois = new ObjectInputStream(bais);
			return ois.readObject();
		} catch (Exception e) {
		    logger.error("反序列化失败", e);
		}
		return null;
	}
}

日期工具类DateUtils:

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import org.apache.commons.lang3.StringUtils;

/**
 * @author 1060771195@qq.com
 */
public class DateUtils {

    final static public String FULL_ST_FORMAT = "yyyy-MM-dd HH:mm:ss";
    final static public String FULL_UTC_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
    final static public String FULL_J_FORMAT = "yyyy/MM/dd HH:mm:ss";
    final static public String CURRENCY_ST_FORMAT = "yyyy-MM-dd HH:mm";
    final static public String CURRENCY_J_FORMAT = "yyyy/MM/dd HH:mm";
    final static public String DATA_FORMAT = "yyyyMMddHHmmss";
    final static public String ST_FORMAT = "yyyy-MM-dd HH:mm";
    final static public String ST_CN_FORMAT = "yyyy年MM月dd日 HH:mm";
    final static public String CN_FORMAT = "yy年MM月dd日HH:mm";
    final static public String DAY_FORMAT = "yyyy-MM-dd";
    final static public String SHORT_DATE_FORMAT = "yy-MM-dd";
    final static public String YEAR_FORMAT = "yyyy";
    final static public String MOUTH_DATE_TIME = "MM-dd HH:mm:ss";
    final static public String MOUTH_DATE = "MM 月dd 日";
    final static public String MOUTH_FORMAT = "yyyy-MM";
    final static public String VAL_TIMESTAMP_FORMAT = "yyyy-MM-dd-HH.mm.ss.SSS";
    final static public String HH_MM_FORMAT = "HH:mm";
    
    public static Date getCurrentTime() {
        return Calendar.getInstance().getTime();
    }
    
    public static Timestamp getCurrentTimestamp() {
        return new Timestamp(System.currentTimeMillis());
    }
    
    public static Timestamp currentTimestamp() {
        return new Timestamp(System.currentTimeMillis());
    }
    
    public static java.sql.Date currentSqlDate() {
        return new java.sql.Date(new Date().getTime());
    }
    
    public static String format() {
        return format(FULL_ST_FORMAT);
    }
    
    public static String format(String pattern) {
        return format(new Date(), pattern);
    }
    
    public static String format(Date date, String pattern) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
        return dateFormat.format(date);
    }
    
    public static Timestamp formatTimestamp(String dateStr, String pattern) {
        if (StringUtils.isBlank(dateStr)) {
            return null;
        }
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        try {
            Date date = format.parse(dateStr);
            return new Timestamp(date.getTime());
        } catch (ParseException e) {
        }
        return null;
    }
    
    public static Date formatDate(String dateStr, String pattern) {
        if (StringUtils.isBlank(dateStr)) {
            return null;
        }
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        try {
            Date date = format.parse(dateStr);
            return date;
        } catch (ParseException e) {}
        return null;
    }
    
    public static java.sql.Date formatSqlDate(String dateStr, String pattern) {
        Date date = formatDate(dateStr, pattern);
        if (null != date) {
            return new java.sql.Date(date.getTime());
        }
        return null;
    }
    
    /**
     * @param itmp 偏移量
     * @return Date 得到变化号数的日期
     */
    public static Date getDate(int itmp) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.DATE, itmp);
        return calendar.getTime();
    }
    
    /**
     * @param itmp 偏移量
     * @return Date 得到变化号数的日期
     */
    public static Date getDate(int itmp, Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, itmp);
        return calendar.getTime();
    }
    
    /**
     * 比较较两个日期,返回天数差
     * @param beginDate 开始日期时间
     * @param endDate 结束日期时间
     */
    public static long compareDay(Date beginDate, Date endDate) {
        Calendar endDateYears = new GregorianCalendar();
        endDateYears.setTime(endDate);
        Calendar beginYears = new GregorianCalendar();
        beginYears.setTime(beginDate);
        long diffMillis = endDateYears.getTimeInMillis()
                - beginYears.getTimeInMillis();
        return diffMillis / (24 * 60 * 60 * 1000);
    }
    
    public static Timestamp getTimestamp(Long time) {
        return new Timestamp(time);
        
    }
    
}

redis工具类RedisRepository:

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;

import yui.comn.utils.SerializeUtils;

/**
 * redis
 * @author 1060771195@qq.com
 */
public class RedisRepository {
    //private static final Logger LOGGER = LoggerFactory.getLogger(RedisRepository.class);

    // -1 - never expire
    private long expire = -1;
    
    //private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

    private RedisTemplate<String, String> redisTemplate;

    public RedisRepository(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public Object get(final String key) throws Exception {
        return redisTemplate.execute(new RedisCallback<Object>() {
            public Object doInRedis(RedisConnection connection)
                    throws DataAccessException {
                byte[] bs = connection.get(key.getBytes());
                return SerializeUtils.deserialize(bs);
            }
        });
    }
    
    public byte[] get(final byte[] key) throws Exception {
        return (byte[]) redisTemplate.execute(new RedisCallback<Object>() {
            public Object doInRedis(RedisConnection connection)
                    throws DataAccessException {
                return connection.get(key);
            }
        });
    }
    
    public Object put(final String key, final Object value) throws Exception {
        return redisTemplate.execute(new RedisCallback<Object>() {
            public Object doInRedis(final RedisConnection connection)
                    throws DataAccessException {
                connection.set(key.getBytes(), SerializeUtils.serialize(value));
                return value;
            }
        });
    }
    
    public Object put(final String key, final Object value, final Long expireSec) throws Exception {
        return redisTemplate.execute(new RedisCallback<Object>() {
            public Object doInRedis(final RedisConnection connection)
                    throws DataAccessException {
                byte[] bKey = key.getBytes();
                connection.set(bKey, SerializeUtils.serialize(value));
                if(null != expireSec) {
                    connection.expire(bKey, expireSec);
                } else {
                    connection.expire(bKey, expire);
                }
                return value;
            }
        });
    }
    
    public Object put(final byte[] key, final byte[] value) throws Exception {
        return redisTemplate.execute(new RedisCallback<Object>() {
            public Object doInRedis(final RedisConnection connection)
                    throws DataAccessException {
                connection.set(key, value);
                return value;
            }
        });
    }
    
    public Object put(final byte[] key, final byte[] value, final Long expireSec) throws Exception {
        return redisTemplate.execute(new RedisCallback<Object>() {
            public Object doInRedis(final RedisConnection connection)
                    throws DataAccessException {
                connection.set(key, value);
                if(null != expireSec) {
                    connection.expire(key, expireSec);
                } else {
                    connection.expire(key, expire);
                }
                return value;
            }
        });
    }

    
    public Long del(final String key) throws Exception {
        return redisTemplate.execute(new RedisCallback<Long>() {
            public Long doInRedis(RedisConnection connection)
                    throws DataAccessException {
                return connection.del(key.getBytes());
            }
        });
    }
    
    public Long del(final byte[] key) throws Exception {
        return redisTemplate.execute(new RedisCallback<Long>() {
            public Long doInRedis(RedisConnection connection)
                    throws DataAccessException {
                return connection.del(key);
            }
        });
    }
    
    
    public void dels(final String pattern) throws Exception {
        redisTemplate.execute(new RedisCallback<Long>() {
            public Long doInRedis(RedisConnection connection)
                    throws DataAccessException {
                Set<byte[]> setByte = connection.keys(pattern.getBytes());
                if (setByte != null && setByte.size() > 0) {
                    for (byte[] key : setByte) {
                        connection.del(key);
                    }
                }
                return null;
            }
        });
    }
    
    public void dels(final byte[] pattern) throws Exception {
        redisTemplate.execute(new RedisCallback<Long>() {
            public Long doInRedis(RedisConnection connection)
                    throws DataAccessException {
                Set<byte[]> setByte = connection.keys(pattern);
                if (setByte != null && setByte.size() > 0) {
                    for (byte[] key : setByte) {
                        connection.del(key);
                    }
                }
                return null;
            }
        });
    }

    @SuppressWarnings("rawtypes")
    public Set keys(final String pattern) throws Exception {
        return redisTemplate.execute(new RedisCallback<Set>() {
            @SuppressWarnings("unchecked")
            public Set doInRedis(RedisConnection connection)
                    throws DataAccessException {
                Set<byte[]> setByte = connection.keys(pattern.getBytes());
                if (setByte == null || setByte.size() < 1) {
                    return Collections.emptySet();
                }
                Set set = new HashSet();
                for (byte[] key : setByte) {
                    byte[] bs = connection.get(key);
                    set.add(SerializeUtils.deserialize(bs));
                }
                return set;
                
            }
        });
    }
    
    @SuppressWarnings("rawtypes")
    public Set keys(final byte[] pattern) throws Exception {
        return redisTemplate.execute(new RedisCallback<Set>() {
            @SuppressWarnings("unchecked")
            public Set doInRedis(RedisConnection connection)
                    throws DataAccessException {
                Set<byte[]> setByte = connection.keys(pattern);
                if (setByte == null || setByte.size() < 1) {
                    return Collections.emptySet();
                }
                Set set = new HashSet();
                for (byte[] key : setByte) {
                    byte[] bs = connection.get(key);
                    set.add(bs);
                }
                return set;

            }
        });
    }

    
    public Object hGet(final byte[] key, final byte[] mapkey) throws Exception {
        return redisTemplate.execute(new RedisCallback<Object>() {
            public Object doInRedis(RedisConnection connection)
                    throws DataAccessException {
                byte[] hGet = connection.hGet(key, mapkey);
                return SerializeUtils.deserialize(hGet);
            }
        });
    }

    
    public Boolean hPut(final byte[] key, final byte[] mapkey, final byte[] value) throws Exception {
        return redisTemplate.execute(new RedisCallback<Boolean>() {
            public Boolean doInRedis(RedisConnection connection)
                    throws DataAccessException {
                Boolean hSet = connection.hSet(key, mapkey, value);
                return hSet;
            }
        });
    }

    @SuppressWarnings("rawtypes")
    
    public Set hKeys(final byte[] pattern) throws Exception {
        return redisTemplate.execute(new RedisCallback<Set>() {
            @SuppressWarnings("unchecked")
            public Set doInRedis(RedisConnection connection)
                    throws DataAccessException {
                Set<byte[]> hKeys = connection.hKeys(pattern);
                if(hKeys == null || hKeys.size()>1){
                    return Collections.emptySet();
                }
                Set set=new HashSet();
                for(byte[] bs:hKeys){
                    set.add(SerializeUtils.deserialize(bs));
                }
                return set;
            }
        });
    }

    
    public Long hDel(final byte[] key, final byte[] mapkey) throws Exception {
        return redisTemplate.execute(new RedisCallback<Long>() {
            public Long doInRedis(RedisConnection connection)
                    throws DataAccessException {
                Long hDel = connection.hDel(key, mapkey);
                return hDel;
            }
        });
    }

    
    public Long hLen(final byte[] key) throws Exception {
        return redisTemplate.execute(new RedisCallback<Long>() {
            public Long doInRedis(RedisConnection connection)
                    throws DataAccessException {
                Long len = connection.hLen(key);
                return len;
            }
        });
    }

    @SuppressWarnings("rawtypes")
    
    public List hVals(final byte[] key) throws Exception {
        return redisTemplate.execute(new RedisCallback<List>() {
            @SuppressWarnings("unchecked")
            public List doInRedis(RedisConnection connection)
                    throws DataAccessException {
                 List<byte[]> hVals = connection.hVals(key);
                
                 if(hVals==null || hVals.size()<1){
                     return Collections.emptyList();
                 }
                 List list = new ArrayList();
                 
                 for(byte[] bs:hVals){
                     list.add(SerializeUtils.deserialize(bs));
                 }
                return list;

            }
        });
    }

    
    public Long dbSize() throws Exception {
        return redisTemplate.execute(new RedisCallback<Long>() {
            public Long doInRedis(RedisConnection connection)
                    throws DataAccessException {
                Long len = connection.dbSize();
                return len;
            }
        });
    }

    
    public void flushDb() throws Exception {
        redisTemplate.execute(new RedisCallback<Long>() {
            public Long doInRedis(RedisConnection connection)
                    throws DataAccessException {
                  connection.flushDb();
                return null;
            }
        });

    }

    
    public void setExpire(long expire) {
        this.expire = expire;
    }

    public void setRedisTemplate(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
}

OrderedPropertiesReader工具类:

import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author 1060771195@qq.com
 */
public class OrderedPropertiesReader {

    private static OrderedPropertiesReader instance = null;

    private static void init() {
        if (instance == null) {
            instance = new OrderedPropertiesReader();
        }
    }

    public static OrderedPropertiesReader getInstance() {
        if (instance == null) {
            init();
        }
        return instance;
    }

    // 直接读取文件中的property
    public String getVal(String fileName, String propertyName) throws IOException {
        InputStream in = OrderedPropertiesReader.class.getResourceAsStream("/"+fileName);
        OrderedProperties prop = new OrderedProperties();
        if (in != null) {
            prop.load(in);
            String value = prop.getProperty(propertyName).trim();
            return value;
        } else {
            throw new IOException();
        }
    }

    // 将propert文件转化为Map
    @SuppressWarnings("unchecked")
    public Map<String, String> getPropertyMap(String fileName) throws IOException {
        Map<String, String> propertyMap = new LinkedHashMap<String, String>();
        InputStream in = OrderedPropertiesReader.class.getResourceAsStream("/"+fileName);
        OrderedProperties prop = new OrderedProperties();
        if (in != null) {
            prop.load(in);
            Set<String> keys=prop.stringPropertyNames();
            //遍历keys获取配置value填入HashMap
            Iterator<String> it = keys.iterator();
            while(it.hasNext()){
                String key=it.next();
                String value=prop.getProperty(key);
                propertyMap.put(key, value);
            }
        }
        return propertyMap;
    }

    // ------------------------------------------private func----------------------------------------------
    
    public static void main(String[] args){
        try {
            OrderedPropertiesReader.getInstance().getPropertyMap("shiroFilterChainDefinition.properties");
            //System.out.println(PropertiesReader.getInstance().getVal("shiroFilterChainDefinition.properties", "fileUploadUrl"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
}

 

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值