SpringBoot+mybatis-plus整合shiro和redis

整合shiro以及将session存入reids中,导入shiro-redis包,就不用自己实现怎么往redis中存session了。现在一般都是前后端分离的项目,后台返回统一的格式给前端

pom



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.6.RELEASE
         
    
    com.pwl
    springboot-shiro
    0.0.1-SNAPSHOT
    springboot-shiro
    Demo project for Spring Boot

    
        1.8
    

    
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        

        
        
            org.apache.shiro
            shiro-spring-boot-starter
            1.4.0
        

        
        
            mysql
            mysql-connector-java
        
        
        
            com.baomidou
            mybatis-plus-boot-starter
            2.2.0
        

        
        
            com.zaxxer
            HikariCP
        

        
            org.apache.velocity
            velocity-engine-core
            2.0
        

        
            org.crazycake
            shiro-redis
            2.4.2.1-RELEASE
            
                
                    org.apache.shiro
                    shiro-core
                
            
        
        
            redis.clients
            jedis
            2.7.2
        

    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


认证类,我用的是mybatis-plus

package com.pwl.shiro.ream;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.pwl.shiro.entity.SysUser;
import com.pwl.shiro.service.SysPermissionService;
import com.pwl.shiro.service.SysUserService;
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.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Pan Weilong
 * @date 2019/6/20 20:11
 * @description: 接口.
 */
public class UserRealm extends AuthorizingRealm{

    private static final Logger LOGGER = LoggerFactory.getLogger(UserRealm.class);
    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private SysPermissionService sysPermissionService;

    /**
     * 授权
     *
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SysUser sysUser = (SysUser) principals.getPrimaryPrincipal();
        //List sysPermissions = sysPermissionService.selectPermissionByUserId(sysUser.getUserId());
        List sysPermissions=new ArrayList<>();
        sysPermissions.add("systemUserAdd");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermissions(sysPermissions);
        LOGGER.info("doGetAuthorizationInfo");
        return info;
    }

    /**
     * 认证
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        Wrapper objectWrapper = new EntityWrapper<>();
        objectWrapper.eq("user_name",token.getUsername());
        SysUser sysUser = sysUserService.selectOne(objectWrapper);
        if (sysUser == null) {
            return null;
        }
        LOGGER.info("doGetAuthenticationInfo");
        return new SimpleAuthenticationInfo(sysUser, sysUser.getPassword().toCharArray(), ByteSource.Util.bytes(sysUser.getSalt()), getName());
    }
}

shiro配置类,很重要

package com.pwl.shiro.config;

import com.pwl.shiro.ream.UserRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

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

/**
 * @author Pan Weilong
 * @date 2019/6/20 20:10
 * @description: 接口.
 */
@Configuration
public class ShiroConfig {


    /**
     * 凭证匹配器
     *
     * @return
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        //md5加密
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        //加密1次
        hashedCredentialsMatcher.setHashIterations(1);
        return hashedCredentialsMatcher;
    }

    /**
     * 自定义realm
     *
     * @return
     */
    @Bean
    public UserRealm userRealm() {
        UserRealm userRealm = new UserRealm();
        userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return userRealm;
    }

    /**
     * 安全管理器
     * 注:使用shiro-spring-boot-starter 1.4时,返回类型是SecurityManager会报错,直接引用shiro-spring则不报错
     *
     * @return
     */
    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm());
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

    /**
     * @Author
     * @Description redis缓存
     * @Date 21:32 2019/6/23
     * @Param []
     * @return org.crazycake.shiro.RedisManager
     **/
    @Bean
    public RedisManager redisManager(){
        RedisManager redisManager = new RedisManager();
        redisManager.setHost("127.0.0.1");
        redisManager.setPort(6379);
        //失效时间30分钟
        redisManager.setExpire(1800);
        return redisManager;
    }

    @Bean
    public RedisSessionDAO redisSessionDAO(){
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        //存入redis前缀
        redisSessionDAO.setKeyPrefix("redis_");
        return redisSessionDAO;
    }

    @Bean
    public RedisCacheManager redisCacheManager(){
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        return redisCacheManager;
    }

    @Bean
    public SessionManager sessionManager() {
        SessionManager sessionManager =new ShiroSessionManager();
        //设置过期时间ms
        ((DefaultWebSessionManager) sessionManager).setGlobalSessionTimeout(1800000);
        //删除无效的session
        ((DefaultWebSessionManager) sessionManager).setDeleteInvalidSessions(Boolean.TRUE);
        //重写url
        ((DefaultWebSessionManager) sessionManager).setSessionIdUrlRewritingEnabled(Boolean.TRUE);
        SimpleCookie simpleCookie = new SimpleCookie();
        simpleCookie.setName("loginUser");
        //设置cookie
        ((DefaultWebSessionManager) sessionManager).setSessionIdCookie(simpleCookie);
        ((DefaultWebSessionManager) sessionManager).setSessionDAO(redisSessionDAO());
        ((DefaultWebSessionManager) sessionManager).setCacheManager(redisCacheManager());
        return sessionManager;
    }


    /**
     * 设置过滤规则
     *
     * @param securityManager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setSuccessUrl("/");
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauth");

        //注意此处使用的是LinkedHashMap,是有顺序的,shiro会按从上到下的顺序匹配验证,匹配了就不再继续验证
        //所以上面的url要苛刻,宽松的url要放在下面,尤其是"/**"要放到最下面,如果放前面的话其后的验证规则就没作用了。
        Map filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/static/**", "anon");
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/captcha.jpg", "anon");
        filterChainDefinitionMap.put("/favicon.ico", "anon");
        filterChainDefinitionMap.put("/**", "authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }
}

 

为了避免session频繁从redis中读取,要重写方法

package com.pwl.shiro.config;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SessionKey;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.session.mgt.WebSessionKey;

import javax.servlet.ServletRequest;
import java.io.Serializable;

/**
 * @author Pan Weilong
 * @date 2019/6/22 10:40
 * @description: 接口.
 */
public class ShiroSessionManager extends DefaultWebSessionManager {

    @Override
    protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {
        Serializable sessionId = getSessionId(sessionKey);

        ServletRequest request = null;
        if (sessionKey instanceof WebSessionKey) {
            request = ((WebSessionKey) sessionKey).getServletRequest();
        }

        if (request != null && null != sessionId) {
            Object sessionObj = request.getAttribute(sessionId.toString());
            if (sessionObj != null) {
                return (Session) sessionObj;
            }
        }

        Session session = super.retrieveSession(sessionKey);
        if (request != null && null != sessionId) {
            request.setAttribute(sessionId.toString(), session);
        }
        return session;
    }
}

 

统一异常处理类

package com.pwl.shiro.exception;

import com.pwl.shiro.common.ResultVO;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;

/**
 * @Author Pan Weilong
 * @Description 全局异常捕获
 * @Date 15:11 2019/6/20
 * @Param
 * @return
 **/
@ControllerAdvice
public class GlobalExceptionHandler implements ApplicationContextAware {

    private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    private ApplicationContext applicationContext;

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ResultVO defaultErrorHandler(HttpServletRequest request, Exception e) throws Exception {
        if(e instanceof UnauthenticatedException){
            return new ResultVO().returnFail(401,"认证失败");
        }else if(e instanceof UnauthorizedException){
            return new ResultVO().returnFail(401,"无权限访问");
        }
        return new ResultVO().returnFail(e.getMessage());
    }

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}
}

返回统一的格式

package com.pwl.shiro.common;

import java.io.Serializable;

/**
 * @author Pan Weilong
 * @date 2019/6/20 15:03
 * @description: 结果统一返回
 */
public class ResultVO implements Serializable {
    private static final long serialVersionUID = 1L;

    public static final int SUCCESS = 200;

    public static final int FAIL = 1;

    private String msg = "success";

    private int code = SUCCESS;

    private T data;

    public ResultVO() {
        super();
    }

    public ResultVO(T data) {
        super();
        this.data = data;
    }

    public ResultVO(T data, String msg) {
        super();
        this.data = data;
        this.msg = msg;
    }

    public ResultVO(Throwable e) {
        super();
        this.msg = e.getMessage();
        this.code = FAIL;
    }

    /**
     *
     * 返回成功
     * @param data
     * @return
     */
    public ResultVO returnSuccess(T data) {
        this.data = data;
        return this;
    }

    /**
     *
     * 返回失败
     *
     * @param code
     * @param msg
     * @return
     */
    public  ResultVO returnFail(Integer code , String msg) {

        this.code = code;

        this.msg = msg;

        return  this;
    }

    public  ResultVO returnFail(String msg) {

        this.code = 500;

        this.msg = msg;

        return  this;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

controller

package com.pwl.shiro.controller;

import com.pwl.shiro.common.ResultVO;
import com.pwl.shiro.entity.SysUser;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.subject.Subject;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

/**
 * @author Pan Weilong
 * @date 2019/6/20 21:00
 * @description: 接口.
 */
@RestController
public class LonginController {

    @GetMapping("/login")
    public ResultVO login(HttpServletRequest request){
        return new ResultVO().returnFail(401,"认证失败");
    }

    @PostMapping("/login")
    public ResultVO login(@RequestBody SysUser sysUser) {
        Subject user = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(sysUser.getUserName(), sysUser.getPassword());
        try {
            //shiro帮我们匹配密码什么的,我们只需要把东西传给它,它会根据我们在UserRealm里认证方法设置的来验证
            user.login(token);
        } catch (Exception e) {
            e.printStackTrace();
            throw new UnauthenticatedException();
        }
        return new ResultVO("登录成功");
    }
}

 

package com.pwl.shiro.controller;


import com.pwl.shiro.common.ResultVO;
import com.pwl.shiro.entity.SysUser;
import com.pwl.shiro.service.SysUserService;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * 

* 前端控制器 *

* * @author pwl * @since 2019-06-20 */ @RestController @RequestMapping("/sysUser") public class SysUserController { @Autowired private SysUserService sysUserService; //需要有systemUser权限才能访问 @RequiresPermissions("systemUserAdd") @GetMapping public ResultVO getUserList(){ List sysUsers = sysUserService.selectList(null); return new ResultVO(sysUsers); } //需要有add权限才能访问 @RequiresPermissions("Add") @GetMapping("/getList") public ResultVO getList(){ List sysUsers = sysUserService.selectList(null); return new ResultVO(sysUsers); } }

首次登陆的时候

SpringBoot+mybatis-plus整合shiro和redis_第1张图片

 

然后登陆

SpringBoot+mybatis-plus整合shiro和redis_第2张图片

最后访问需要某些权限的接口

SpringBoot+mybatis-plus整合shiro和redis_第3张图片

当用户没有权限的时候访问接口

SpringBoot+mybatis-plus整合shiro和redis_第4张图片

贴的部分代码

sql及项目地址:https://github.com/James-Pan0525/springboot-shiro-pwl.git

你可能感兴趣的:(shiro)