SpringBoot之集成Shiro

一、Shiro

    Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
主要功能
    三个核心组件:Subject, SecurityManager 和 Realms.
    Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。
    Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
    SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
    Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
    从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
    Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。

二、Maven包引入
     <dependency>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-spring</artifactId>
         <version>${shiro.version}</version>
     </dependency>
三、注解配置
package com.zxhy.shiro.config;

import com.zxhy.shiro.filter.RememberAuthenticationFilter;
import com.zxhy.shiro.realm.MyRealm;
import com.zxhy.shiro.redisSession.CachingShiroSessionDao;
import com.zxhy.shiro.redisSession.SessionManager;
import com.zxhy.shiro.redisSession.ShiroSessionListener;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.mgt.SecurityManager;

import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;


@Configuration
public class ShiroConfig {
	//权限过滤器的工厂类
    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //拦截器.
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        // 配置不会被拦截的链接 顺序判断
        filterChainDefinitionMap.put("/app/**", "anon");
        filterChainDefinitionMap.put("/service/**", "anon");
        filterChainDefinitionMap.put("/statics/**", "anon");
        filterChainDefinitionMap.put("/static/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/index.html", "anon");
        filterChainDefinitionMap.put("/login/login", "anon");
        filterChainDefinitionMap.put("/login/captcha", "anon");
        filterChainDefinitionMap.put("/swagger/**", "anon");
        filterChainDefinitionMap.put("/**", "rememberAuthFilter");

        Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
        filters.put("rememberAuthFilter",new RememberAuthenticationFilter());
        shiroFilterFactoryBean.setLoginUrl("/index.html");
        // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/index1.html");
        //未授权界面;
        shiroFilterFactoryBean.setUnauthorizedUrl("/");
        shiroFilterFactoryBean.setFilters(filters);
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }
	//设置Realms以及session管理器
    @Bean
    public SecurityManager securityManager(SessionManager sessionManager, MyRealm myRealm ) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myRealm);
        securityManager.setSessionManager(sessionManager);
        return securityManager;
    }
	//配置session管理器
    @Bean
    public SessionManager sessionManager(SimpleCookie sessionIdCookie,CachingShiroSessionDao sessionDao,SessionListener sessionListener) {
        SessionManager sessionManager = new SessionManager();
        sessionManager.setDeleteInvalidSessions(false);
        sessionManager.setGlobalSessionTimeout(7200000);
        sessionManager.setSessionValidationSchedulerEnabled(false);
        sessionManager.setSessionValidationInterval(1800000);
        sessionManager.setSessionDAO(sessionDao);
        sessionManager.setSessionIdCookieEnabled(true);
        sessionManager.setSessionIdCookie(sessionIdCookie);
        List<SessionListener> sessionListeners = new ArrayList<>();
        sessionListeners.add(sessionListener);
        sessionManager.setSessionListeners(sessionListeners);
        return sessionManager;
    }
    //配置session缓存管理器
    @Bean
    public CachingShiroSessionDao sessionDao() {
        CachingShiroSessionDao sessionDao = new CachingShiroSessionDao();
        sessionDao.setPrefix("shiro-session:");
        sessionDao.setSeconds(1800);
        return sessionDao;
    }
	//配置cookies
    @Bean
    public SimpleCookie sessionIdCookie() {
        SimpleCookie simpleCookie = new SimpleCookie("sid");
        //simpleCookie.setDomain(".sojson.com");
        simpleCookie.setMaxAge(-1);
        simpleCookie.setHttpOnly(true);
        return simpleCookie;
    }
    //配置session监听器
    @Bean
    public SessionListener sessionListener() {
        return new ShiroSessionListener();
    }
}
四、添加必要的配置类

添加一个判断用户可否登陆的过滤器,这个不是必须的,个人按情况添加。

package com.zxhy.shiro.filter;

import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 * 类的功能描述.
 *
 * @Date 2017/5/17
 */

public class RememberAuthenticationFilter extends FormAuthenticationFilter{

    /**
     * 这个方法决定了是否能让用户登录
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        Subject subject = getSubject(request, response);
        //如果 isAuthenticated 为 false 证明不是登录过的,同时 isRememberd 为true 证明是没登陆直接通过记住我功能进来的
        if(!subject.isAuthenticated() && subject.isRemembered()){
            //获取session看看是不是空的
            Session session = subject.getSession();
            //随便拿session的一个属性来看session当前是否是空的,我用userId,你们的项目可以自行发挥
            if(session.getAttribute("user") == null){
                //如果是空的才初始化,否则每次都要初始化,项目得慢死
                //这边根据前面的前提假设,拿到的是username
//                UserEntity userEntity = (UserEntity) subject.getPrincipal();
//                session.setAttribute("user",userEntity);
                //在这个方法里面做初始化用户上下文的事情,比如通过查询数据库来设置session值,你们自己发挥
                //globalUserService.initUserContext(username, subject);
            }
        }
        //这个方法本来只返回 subject.isAuthenticated() 现在我们加上 subject.isRemembered() 让它同时也兼容remember这种情况
        return subject.isAuthenticated() || subject.isRemembered();
    }

}

添加自己的权限验证类MyRealm

package com.zxhy.shiro.realm;

import com.zxhy.base.common.Constant;

import com.zxhy.sys.entity.MenuEntity;
import com.zxhy.sys.entity.RoleEntity;
import com.zxhy.sys.entity.UserEntity;
import com.zxhy.sys.service.MenuService;
import com.zxhy.sys.service.RoleService;
import com.zxhy.sys.service.UserRoleService;
import com.zxhy.sys.service.UserService;
import com.zxhy.utils.ShiroUtils;
import com.zxhy.utils.UsernamePasswordLoginTypeToken;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.AllowAllCredentialsMatcher;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 类的功能描述.
 * shiro 认证
 * @Auther zxhy
 * @Date 2017/4/27
 */

@Component
public class MyRealm extends AuthorizingRealm {

    private static final Logger logger = LoggerFactory.getLogger(MyRealm.class);
    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private MenuService menuService;
    @Autowired
    private UserRoleService userRoleService;

    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            UserEntity user = (UserEntity) principals.getPrimaryPrincipal();
            if(user !=null){
                //根据用户id查询该用户所有的角色,并加入到shiro的SimpleAuthorizationInfo
                List<RoleEntity> roles = roleService.queryByUserId(user.getId(), Constant.YESNO.YES.getValue());
                for (RoleEntity role:roles){
                    info.addRole(role.getId());
                }
                //查询所有该用户授权菜单,并加到shiro的SimpleAuthorizationInfo 做菜单按钮权限控件

                Set<String> permissions = new HashSet<>();
                List<MenuEntity> menuEntities=null;
                //超级管理员拥有最高权限
                if(Constant.SUPERR_USER.equals(user.getId())){
                    menuEntities = menuService.queryList(new HashMap<String,Object>());
                }else{
                    //普通帐户权限查询
                    menuEntities = menuService.queryByUserId(user.getId());
                }
                for (MenuEntity menuEntity:menuEntities){
                    if(StringUtils.isNotEmpty(menuEntity.getPermission())){
                        for(String per : menuEntity.getPermission().split(",")){
                            permissions.add(per);
                        }
                    }
                }
                info.addStringPermissions(permissions);
            }
            return info;
    }

    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String userLoginName= (String) token.getPrincipal();
        UserEntity user = userService.queryByLoginName(userLoginName);
        if(user == null){
            throw new AuthenticationException("帐号密码错误");
        }
        if(Constant.ABLE_STATUS.NO.getValue().equals(user.getStatus())){
            throw new LockedAccountException("帐号被禁用,请联系管理员!");
        }
        //用户对应的机构集合
        List<String> baidList = userService.queryBapidByUserIdArray(user.getId());
        //用户对应的部门集合
        List<String> bapidList= userService.queryBaidByUserIdArray(user.getId());
        //用户对应的电站集合
        List<String> stationList= userService.queryStationByUserIdArray(user.getId());
        user.setRoleIdList(userRoleService.queryRoleIdList(user.getId()));
        user.setBapidList(bapidList);
        user.setBaidList(baidList);
        user.setStationIds(stationList);
        SimpleAuthenticationInfo sainfo = new SimpleAuthenticationInfo(user,user.getPassWord(), ByteSource.Util.bytes(user.getSalt()),getName());
        return sainfo;
    }

    @Override
    public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
        HashedCredentialsMatcher shaCredentialsMatcher = new HashedCredentialsMatcher();
        shaCredentialsMatcher.setHashAlgorithmName(ShiroUtils.algorithmName);
        shaCredentialsMatcher.setHashIterations(ShiroUtils.hashIterations);
        super.setCredentialsMatcher(shaCredentialsMatcher);
    }
    @Override
    protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException{
        UsernamePasswordLoginTypeToken tokenType = (UsernamePasswordLoginTypeToken) token;
        CredentialsMatcher cm = this.getCredentialsMatcher();
        if (cm != null) {
            if(!"1".equals(tokenType.getLoginType().getCode())){
                if (!cm.doCredentialsMatch(token, info)) {
                    String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials.";
                    throw new IncorrectCredentialsException(msg);
                }
            }
        } else {
            throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify credentials during authentication.  If you do not wish for credentials to be examined, you can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance.");
        }



    }
}

添加session的缓存管理类,这个是用redis缓存的

package com.zxhy.shiro.redisSession;


import com.zxhy.base.utils.SerializeUtil;
import com.zxhy.utils.RedisUtil;
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.ValidatingSession;
import org.apache.shiro.session.mgt.eis.CachingSessionDAO;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.Serializable;

/**
 * 针对自定义的ShiroSession的Redis CRUD操作,通过isChanged标识符,确定是否需要调用Update方法
 * 通过配置securityManager在属性cacheManager查找从缓存中查找Session是否存在,如果找不到才调用下面方法
 * Shiro内部相应的组件(DefaultSecurityManager)会自动检测相应的对象(如Realm)是否实现了CacheManagerAware并自动注入相应的CacheManager。
 */
@Component
public class CachingShiroSessionDao extends CachingSessionDAO {

    private static final Logger logger = LoggerFactory.getLogger(CachingShiroSessionDao.class);

    @Autowired
    private RedisUtil redisUtil;

    // 保存到Redis中key的前缀 prefix+sessionId
    private String prefix = "";

    // 设置会话的过期时间
    private int seconds = 0;

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    public void setSeconds(int seconds) {
        this.seconds = seconds;
    }

    /**
     * 重写CachingSessionDAO中readSession方法,如果Session中没有登陆信息就调用doReadSession方法从Redis中重读
     */
    @Override
    public Session readSession(Serializable sessionId) throws UnknownSessionException {
        Session session = getCachedSession(sessionId);
        if (session == null
                || session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY) == null) {
            session = this.doReadSession(sessionId);
            if (session == null) {
                throw new UnknownSessionException("There is no session with id [" + sessionId + "]");
            } else {
                // 缓存
                cache(session, session.getId());
            }
        }
        return session;
    }

    /**
     * 根据会话ID获取会话
     *
     * @param sessionId 会话ID
     * @return ShiroSession
     */
    @Override
    protected Session doReadSession(Serializable sessionId) {
        Session session = null;
        String key = prefix + sessionId;
        try {
            if( redisUtil.get(key) != null ){
                session = (Session) SerializeUtil.deserialize(redisUtil.get(key).toString());
            }else{
                logger.warn("读取Session失效,sessionId:"+sessionId);
            }
            //logger.info("sessionId {} name {} 被读取", sessionId, session.getClass().getName());
        } catch (Exception e) {
            logger.warn("读取Session失败,sessionId:"+sessionId, e);
        }
        return session;
    }

    /**
     * 如DefaultSessionManager在创建完session后会调用该方法;
     * 如保存到关系数据库/文件系统/NoSQL数据库;即可以实现会话的持久化;
     * 返回会话ID;主要此处返回的ID.equals(session.getId());
     */
    @Override
    protected Serializable doCreate(Session session) {
        // 创建一个Id并设置给Session
        Serializable sessionId = this.generateSessionId(session);
        assignSessionId(session, sessionId);
        try {
            // session由Redis缓存失效决定,这里只是简单标识
            session.setTimeout(seconds);
            redisUtil.set(prefix + sessionId,SerializeUtil.serialize(session),seconds);
            logger.info("sessionId {} name {} 被创建", sessionId, session.getClass().getName());
        } catch (Exception e) {
            logger.warn("创建Session失败", e);
        }
        return sessionId;
    }

    /**
     * 更新会话;如更新会话最后访问时间/停止会话/设置超时时间/设置移除属性等会调用
     */
    @Override
    protected void doUpdate(Session session) {
        //如果会话过期/停止 没必要再更新了
        try {
            if (session instanceof ValidatingSession && !((ValidatingSession) session).isValid()) {
                return;
            }
        } catch (Exception e) {
            logger.error("ValidatingSession error");
        }
        try {
            try {
                redisUtil.set(prefix+session.getId(), SerializeUtil.serialize(session),seconds);
                //logger.info("sessionId {} name {} 被更新", session.getId(), session.getClass().getName());
            } catch (Exception e) {
                logger.info("sessionId {} name {} 更新异常", session.getId(), session.getClass().getName());
                throw e;
            }
        } catch (Exception e) {
            logger.warn("更新Session失败", e);
        }
    }

    /**
     * 删除会话;当会话过期/会话停止(如用户退出时)会调用
     */
    @Override
    protected void doDelete(Session session) {
        try {
            redisUtil.del(prefix + session.getId());
            logger.debug("Session {} 被删除", session.getId());
        } catch (Exception e) {
            logger.warn("删除Session失败", e);
        }
    }

    /**
     * 删除cache中缓存的Session
     */
    public void uncache(Serializable sessionId) {
        Session session = this.readSession(sessionId);
        super.uncache(session);
        logger.info("取消session {} 的缓存", sessionId);
    }

    /**
     * 获取当前所有活跃用户,如果用户量多此方法影响性能
     */
   /* @Override
    public Collection<Session> getActiveSessions() {
        Jedis jedis = null;
        try {
            jedis = jedisUtils.getResource();
            Set<String> keys = jedis.keys(prefix + "*");
            if (CollectionUtils.isEmpty(keys)) {
                return null;
            }
            List<String> valueList = jedis.mget(keys.toArray(new String[0]));
            return SerializeUtils.deserializeFromStringController(valueList);
        } catch (Exception e) {
            logger.warn("统计Session信息失败", e);
        } finally {
            jedisUtils.returnResource(jedis);
        }
        return null;
    }*/

}

添加session的管理类

/**
 * @Title:
 * @Author:admin
 * @Version:1.0
 * @Date:2018/8/14
 * @Company:陕西致信恒源能源科技有限责任公司
 */
package com.zxhy.shiro.redisSession;

import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;

/**
 * Created by Palerock
 */
public class SessionManager extends DefaultWebSessionManager {
    private static final Logger log = LoggerFactory.getLogger(DefaultWebSessionManager.class);
    private String authorization = "X-Token";

    /**
     * 重写获取sessionId的方法调用当前Manager的获取方法
     *
     * @param request
     * @param response
     * @return
     */
    @Override
    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
        return this.getReferencedSessionId(request, response);
    }

    /**
     * 获取sessionId从请求中
     *
     * @param request
     * @param response
     * @return
     */
    private Serializable getReferencedSessionId(ServletRequest request, ServletResponse response) {
        String id = this.getSessionIdCookieValue(request, response);
        if (id != null) {
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, "cookie");
        } else {
            id = this.getUriPathSegmentParamValue(request, "JSESSIONID");
            if (id == null) {
                // 获取请求头中的session
                id = WebUtils.toHttp(request).getHeader(this.authorization);
                if (id == null) {
                    String name = this.getSessionIdName();
                    id = request.getParameter(name);
                    if (id == null) {
                        id = request.getParameter(name.toLowerCase());
                    }
                }
            }
            if (id != null) {
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, "url");
            }
        }

        if (id != null) {
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
        }

        return id;
    }

    // copy super
    private String getSessionIdCookieValue(ServletRequest request, ServletResponse response) {
        if (!this.isSessionIdCookieEnabled()) {
            log.debug("Session ID cookie is disabled - session id will not be acquired from a request cookie.");
            return null;
        } else if (!(request instanceof HttpServletRequest)) {
            log.debug("Current request is not an HttpServletRequest - cannot get session ID cookie.  Returning null.");
            return null;
        } else {
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            return this.getSessionIdCookie().readValue(httpRequest, WebUtils.toHttp(response));
        }
    }

    // copy super
    private String getUriPathSegmentParamValue(ServletRequest servletRequest, String paramName) {
        if (!(servletRequest instanceof HttpServletRequest)) {
            return null;
        } else {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            String uri = request.getRequestURI();
            if (uri == null) {
                return null;
            } else {
                int queryStartIndex = uri.indexOf(63);
                if (queryStartIndex >= 0) {
                    uri = uri.substring(0, queryStartIndex);
                }

                int index = uri.indexOf(59);
                if (index < 0) {
                    return null;
                } else {
                    String TOKEN = paramName + "=";
                    uri = uri.substring(index + 1);
                    index = uri.lastIndexOf(TOKEN);
                    if (index < 0) {
                        return null;
                    } else {
                        uri = uri.substring(index + TOKEN.length());
                        index = uri.indexOf(59);
                        if (index >= 0) {
                            uri = uri.substring(0, index);
                        }

                        return uri;
                    }
                }
            }
        }
    }

    // copy super
    private String getSessionIdName() {
        String name = this.getSessionIdCookie() != null ? this.getSessionIdCookie().getName() : null;
        if (name == null) {
            name = "JSESSIONID";
        }
        return name;
    }
}

最后添加session的监听器

package com.zxhy.shiro.redisSession;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.SessionListenerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * 类ShiroSessionListener的功能描述:
 * 发现用户登出后,Session没有从Redis中销毁,虽然当前重新new了一个,但会对统计带来干扰,通过SessionListener解决这个问题
 * @auther zxhy
 * @date 2017-09-25 11:45:11
 */
public class ShiroSessionListener extends SessionListenerAdapter {

    private static final Logger logger = LoggerFactory.getLogger(ShiroSessionListener.class);

    @Autowired
    private CachingShiroSessionDao sessionDao;

    @Override
    public void onStart(Session session) {
        // 会话创建时触发
        logger.info("ShiroSessionListener session {} 被创建", session.getId());
    }

    @Override
    public void onStop(Session session) {
        sessionDao.delete(session);
        // 会话被停止时触发
        logger.info("ShiroSessionListener session {} 被销毁", session.getId());
    }

    @Override
    public void onExpiration(Session session) {
        sessionDao.delete(session);
        //会话过期时触发
        logger.info("ShiroSessionListener session {} 过期", session.getId());
    }
}

这样就完成了整个Shiro的集成

五、添加方便操作的Shiro工具类
package com.zxhy.utils;

import com.zxhy.sys.entity.UserEntity;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;


/**
 * 类ShiroUtils的功能描述:
 * Shiro工具类
 * @auther zxhy
 * @date 2017-08-25 16:19:35
 */
public class ShiroUtils {

	/**  加密算法 */
	public final static String algorithmName = "SHA-256";
	/**
	 * 加密散列次数
	 */
	public static final int hashIterations= 1;

	public static String EncodeSalt(String password, String salt) {
		return new SimpleHash(algorithmName, password, salt, hashIterations).toString();
	}

	public static Session getSession() {
		return SecurityUtils.getSubject().getSession();
	}

	public static Subject getSubject() {
		return SecurityUtils.getSubject();
	}

	public static UserEntity getUserEntity() {
		return (UserEntity) SecurityUtils.getSubject().getPrincipal();
	}

	public static String getUserId() {
		return getUserEntity().getId();
	}
	
	public static void setSessionAttribute(Object key, Object value) {
		getSession().setAttribute(key, value);
	}

	public static Object getSessionAttribute(Object key) {
		return getSession().getAttribute(key);
	}

	public static boolean isLogin() {
		return SecurityUtils.getSubject().getPrincipal() != null;
	}

	public static void logout() {
		SecurityUtils.getSubject().logout();
	}
	
	public static String getKaptcha(String key) {
		String kaptcha = getSessionAttribute(key).toString();
		getSession().removeAttribute(key);
		return kaptcha;
	}

}

六、登录测试和用注解@RequiresPermissions添加权限测试
    /**
     * 登录
     */
    @ResponseBody
    @RequestMapping(value = "/login/login", method = RequestMethod.POST)
    public Result login(@RequestBody UserEntity userEntity, String captcha, boolean isRememberMe) throws IOException {
        try {
            UsernamePasswordLoginTypeToken token = token = new UsernamePasswordLoginTypeToken(userEntity.getLoginName(), userEntity.getPassWord());
            Subject subject = ShiroUtils.getSubject();
            token.setRememberMe(isRememberMe);
            subject.login(token);
        } catch (UnknownAccountException e) {
            return Result.error(e.getMessage());
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            return Result.error("账号或密码不正确!");
        } catch (LockedAccountException e) {
            return Result.error("账号已被锁定,请联系管理员!");
        } catch (AuthenticationException e) {
            return Result.error(e.getMessage());
        }
        }
        return Result.ok(map);
    }
    /**
	 * 信息
	 */
	@RequestMapping("/info/{id}")
	@RequiresPermissions("sys:code:info")
	@SysLog("查看字典")
	public Result info(@PathVariable("id") String id){
		CodeEntity code = codeService.queryObject(id);
		
		return Result.ok().put("code", code);
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值