SpringBoot+mybatis-plus整合shiro和redis

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

让客户满意是我们工作的目标,不断超越客户的期望值来自于我们对这个行业的热爱。我们立志把好的技术通过有效、简单的方式提供给客户,将通过不懈努力成为客户在信息化领域值得信任、有价值的长期合作伙伴,公司提供的服务项目有:域名注册、网页空间、营销软件、网站建设、莱阳网站维护、网站推广。

pom

xsi:schemaLocation=

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;

}

/**

*无锡人流医院 http://www.bhnkyy39.com/

* 返回失败

*

* @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);

}

}

首次登陆的时候

然后登陆

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

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

贴的部分代码

sql及项目地址


标题名称:SpringBoot+mybatis-plus整合shiro和redis
本文路径:http://ybzwz.com/article/iicepg.html