本来是想学习shiro的,不过后来发现竟然一次性能学到。具体能学到哪些呢?哈哈,看标题吧。如果有什么知识点没看懂的,欢迎私信我!
注明链接,感谢大牛:https://www.cnblogs.com/javazhiyin/p/11398374.html。这里有git地址,也有源码,大家认真翻阅,定会大有收获!
项目目录结构:
启动类代码:
package com.sh.demo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
@MapperScan(basePackages = {"com.sh.demo.core.dao"}) //扫描DAO
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext app = SpringApplication.run(DemoApplication.class, args);
}
}
shiro配置类:
package com.sh.demo.common.config;
import com.sh.demo.common.shiro.ShiroRealm;
import com.sh.demo.common.shiro.ShiroSessionIdGenerator;
import com.sh.demo.common.shiro.ShiroSessionManager;
import com.sh.demo.common.util.SHA256Util;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @Description Shiro配置类
* @Author Sans
* @CreateTime 2019/6/10 17:42
*/
@Configuration
public class ShiroConfig {
private final String CACHE_KEY = "shiro:cache:";
private final String SESSION_KEY = "shiro:session:";
//Redis配置
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.timeout}")
private int timeout;
@Value("${spring.redis.password}")
private String password;
/**
* 开启Shiro-aop注解支持
* @Attention 使用代理方式所以需要开启代码支持
* @Author Sans
* @CreateTime 2019/6/12 8:38
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
/**
* Shiro基础配置
* @Author Sans
* @CreateTime 2019/6/12 8:42
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactory(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
// 注意过滤器配置顺序不能颠倒
// 配置过滤:不会被拦截的链接
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/userLogin/**", "anon");
filterChainDefinitionMap.put("/**", "authc");
// 配置shiro默认登录界面地址,前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据
shiroFilterFactoryBean.setLoginUrl("/userLogin/unauth");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
/**
* 安全管理器
* @Author Sans
* @CreateTime 2019/6/12 10:34
*/
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 自定义Ssession管理
securityManager.setSessionManager(sessionManager());
// 自定义Cache实现
securityManager.setCacheManager(cacheManager());
// 自定义Realm验证
securityManager.setRealm(shiroRealm());
return securityManager;
}
/**
* 身份验证器
* @Author Sans
* @CreateTime 2019/6/12 10:37
*/
@Bean
public ShiroRealm shiroRealm() {
ShiroRealm shiroRealm = new ShiroRealm();
shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return shiroRealm;
}
/**
* 凭证匹配器
* 将密码校验交给Shiro的SimpleAuthenticationInfo进行处理,在这里做匹配配置
* @Author Sans
* @CreateTime 2019/6/12 10:48
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher shaCredentialsMatcher = new HashedCredentialsMatcher();
// 散列算法:这里使用SHA256算法;
shaCredentialsMatcher.setHashAlgorithmName(SHA256Util.HASH_ALGORITHM_NAME);
// 散列的次数,比如散列两次,相当于 md5(md5(""));
shaCredentialsMatcher.setHashIterations(SHA256Util.HASH_ITERATIONS);
return shaCredentialsMatcher;
}
/**
* 配置Redis管理器
* @Attention 使用的是shiro-redis开源插件
* @Author Sans
* @CreateTime 2019/6/12 11:06
*/
@Bean
public RedisManager redisManager() {
RedisManager redisManager = new RedisManager();
redisManager.setHost(host);
redisManager.setPort(port);
redisManager.setTimeout(timeout);
redisManager.setPassword(password);
return redisManager;
}
/**
* 配置Cache管理器
* 用于往Redis存储权限和角色标识
* @Attention 使用的是shiro-redis开源插件
* @Author Sans
* @CreateTime 2019/6/12 12:37
*/
@Bean
public RedisCacheManager cacheManager() {
RedisCacheManager redisCacheManager = new RedisCacheManager();
redisCacheManager.setRedisManager(redisManager());
redisCacheManager.setKeyPrefix(CACHE_KEY);
// 配置缓存的话要求放在session里面的实体类必须有个id标识
redisCacheManager.setPrincipalIdFieldName("userId");
return redisCacheManager;
}
/**
* SessionID生成器
* @Author Sans
* @CreateTime 2019/6/12 13:12
*/
@Bean
public ShiroSessionIdGenerator sessionIdGenerator(){
return new ShiroSessionIdGenerator();
}
/**
* 配置RedisSessionDAO
* @Attention 使用的是shiro-redis开源插件
* @Author Sans
* @CreateTime 2019/6/12 13:44
*/
@Bean
public RedisSessionDAO redisSessionDAO() {
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisManager(redisManager());
redisSessionDAO.setSessionIdGenerator(sessionIdGenerator());
redisSessionDAO.setKeyPrefix(SESSION_KEY);
redisSessionDAO.setExpire(timeout);
return redisSessionDAO;
}
/**
* 配置Session管理器
* @Author Sans
* @CreateTime 2019/6/12 14:25
*/
@Bean
public SessionManager sessionManager() {
ShiroSessionManager shiroSessionManager = new ShiroSessionManager();
shiroSessionManager.setSessionDAO(redisSessionDAO());
return shiroSessionManager;
}
}
RedisConstant类:
package com.sh.demo.common.constant;
/**
* @Description redis常量类
* @Author Sans
* @CreateTime 2019/6/11 10:04
*/
public interface RedisConstant {
/**
* TOKEN前缀
*/
String REDIS_PREFIX_LOGIN = "login_token_%s";
/**
* 过期时间2小时
*/
Integer REDIS_EXPIRE_TWO = 7200;
/**
* 过期时间15分
*/
Integer REDIS_EXPIRE_EMAIL = 900;
/**
* 过期时间5分钟
*/
Integer REDIS_EXPIRE_KAPTCHA = 300;
/**
* 暂无过期时间
*/
Integer REDIS_EXPIRE_NULL = -1;
}
异常控制类:
package com.sh.demo.common.exception;
import org.apache.shiro.authz.AuthorizationException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;
/**
* @Description 自定义异常
* @Author Sans
* @CreateTime 2019/6/15 22:56
*/
@ControllerAdvice
public class MyShiroException {
/**
* 处理Shiro权限拦截异常
* 如果返回JSON数据格式请加上 @ResponseBody注解
* @Author Sans
* @CreateTime 2019/6/15 13:35
* @Return Map<Object> 返回结果集
*/
@ResponseBody
@ExceptionHandler(value = AuthorizationException.class)
public Map<String,Object> defaultErrorHandler(){
Map<String,Object> map = new HashMap<>();
map.put("403","权限不足");
return map;
}
}
ShiroRealm:
package com.sh.demo.common.shiro;
import com.sh.demo.common.util.ShiroUtils;
import com.sh.demo.core.entity.SysMenuEntity;
import com.sh.demo.core.entity.SysRoleEntity;
import com.sh.demo.core.entity.SysUserEntity;
import com.sh.demo.core.service.SysMenuService;
import com.sh.demo.core.service.SysRoleService;
import com.sh.demo.core.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.springframework.beans.factory.annotation.Autowired;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @Description Shiro权限匹配和账号密码匹配
* @Author Sans
* @CreateTime 2019/6/15 11:27
*/
public class ShiroRealm extends AuthorizingRealm {
@Autowired
private SysUserService sysUserService;
@Autowired
private SysRoleService sysRoleService;
@Autowired
private SysMenuService sysMenuService;
/**
* 授权权限
* 用户进行权限验证时候Shiro会去缓存中找,如果查不到数据,会执行这个方法去查权限,并放入缓存中
* @Author Sans
* @CreateTime 2019/6/12 11:44
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取用户ID
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
SysUserEntity sysUserEntity = (SysUserEntity) principalCollection.getPrimaryPrincipal();
Long userId =sysUserEntity.getUserId();
//这里可以进行授权和处理
Set<String> rolesSet = new HashSet<>();
Set<String> permsSet = new HashSet<>();
//查询角色和权限(这里根据业务自行查询)
List<SysRoleEntity> sysRoleEntityList = sysRoleService.selectSysRoleByUserId(userId);
for (SysRoleEntity sysRoleEntity:sysRoleEntityList) {
rolesSet.add(sysRoleEntity.getRoleName());
List<SysMenuEntity> sysMenuEntityList = sysMenuService.selectSysMenuByRoleId(sysRoleEntity.getRoleId());
for (SysMenuEntity sysMenuEntity :sysMenuEntityList) {
permsSet.add(sysMenuEntity.getPerms());
}
}
//将查到的权限和角色分别传入authorizationInfo中
authorizationInfo.setStringPermissions(permsSet);
authorizationInfo.setRoles(rolesSet);
return authorizationInfo;
}
/**
* 身份认证
* @Author Sans
* @CreateTime 2019/6/12 12:36
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//获取用户的输入的账号.
String username = (String) authenticationToken.getPrincipal();
//通过username从数据库中查找 User对象,如果找到进行验证
//实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
SysUserEntity user = sysUserService.selectUserByName(username);
//判断账号是否存在
if (user == null) {
throw new AuthenticationException();
}
//判断账号是否被冻结
if (user.getState()==null||user.getState().equals("PROHIBIT")){
throw new LockedAccountException();
}
//进行验证
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
user, //用户名
user.getPassword(), //密码
ByteSource.Util.bytes(user.getSalt()), //设置盐值
getName()
);
//验证成功开始踢人(清除缓存和Session)
ShiroUtils.deleteCache(username,true);
return authenticationInfo;
}
}
自定义ID生成器:
package com.sh.demo.common.shiro;
import com.sh.demo.common.constant.RedisConstant;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
import org.apache.shiro.session.mgt.eis.SessionIdGenerator;
import java.io.Serializable;
/**
* @Description 自定义SessionId生成器
* @Author Sans
* @CreateTime 2019/6/11 11:48
*/
public class ShiroSessionIdGenerator implements SessionIdGenerator {
/**
* 实现SessionId生成
* @Author Sans
* @CreateTime 2019/6/11 11:54
*/
@Override
public Serializable generateId(Session session) {
Serializable sessionId = new JavaUuidSessionIdGenerator().generateId(session);
return String.format(RedisConstant.REDIS_PREFIX_LOGIN, sessionId);
}
}
ShiroSessonManger:
package com.sh.demo.common.shiro;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable;
/**
* @Description 自定义获取Token
* @Author Sans
* @CreateTime 2019/6/13 8:34
*/
public class ShiroSessionManager extends DefaultWebSessionManager {
//定义常量
private static final String AUTHORIZATION = "Authorization";
private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
//重写构造器
public ShiroSessionManager() {
super();
this.setDeleteInvalidSessions(true);
}
/**
* 重写方法实现从请求头获取Token便于接口统一
* 每次请求进来,Shiro会去从请求头找Authorization这个key对应的Value(Token)
* @Author Sans
* @CreateTime 2019/6/13 8:47
*/
@Override
public Serializable getSessionId(ServletRequest request, ServletResponse response) {
String token = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
//如果请求头中存在token 则从请求头中获取token
if (!StringUtils.isEmpty(token)) {
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, token);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
return token;
} else {
// 这里禁用掉Cookie获取方式
// 按默认规则从Cookie取Token
// return super.getSessionId(request, response);
return null;
}
}
}
接下来是3个工具类:
package com.sh.demo.common.util;
import org.apache.shiro.crypto.hash.SimpleHash;
/**
* @Description Sha-256加密工具
* @Author Sans
* @CreateTime 2019/6/12 9:27
*/
public class SHA256Util {
/** 私有构造器 **/
private SHA256Util(){};
/** 加密算法 **/
public final static String HASH_ALGORITHM_NAME = "SHA-256";
/** 循环次数 **/
public final static int HASH_ITERATIONS = 15;
/** 执行加密-采用SHA256和盐值加密 **/
public static String sha256(String password, String salt) {
return new SimpleHash(HASH_ALGORITHM_NAME, password, salt, HASH_ITERATIONS).toString();
}
}
package com.sh.demo.common.util;
import com.sh.demo.core.entity.SysUserEntity;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.Authenticator;
import org.apache.shiro.authc.LogoutAware;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.RedisSessionDAO;
import java.util.Collection;
import java.util.Objects;
/**
* @Description Shiro工具类
* @Author Sans
* @CreateTime 2019/6/15 16:11
*/
public class ShiroUtils {
/** 私有构造器 **/
private ShiroUtils(){ }
private static RedisSessionDAO redisSessionDAO = SpringUtil.getBean(RedisSessionDAO.class);
/**
* 获取当前用户Session
* @Author Sans
* @CreateTime 2019/6/17 17:03
* @Return SysUserEntity 用户信息
*/
public static Session getSession() {
return SecurityUtils.getSubject().getSession();
}
/**
* 用户登出
* @Author Sans
* @CreateTime 2019/6/17 17:23
*/
public static void logout() {
SecurityUtils.getSubject().logout();
}
/**
* 获取当前用户信息
* @Author Sans
* @CreateTime 2019/6/17 17:03
* @Return SysUserEntity 用户信息
*/
public static SysUserEntity getUserInfo() {
return (SysUserEntity) SecurityUtils.getSubject().getPrincipal();
}
/**
* 删除用户缓存信息
* @Author Sans
* @CreateTime 2019/6/17 13:57
* @Param username 用户名称
* @Param isRemoveSession 是否删除Session
* @Return void
*/
public static void deleteCache(String username, boolean isRemoveSession){
//从缓存中获取Session
Session session = null;
Collection<Session> sessions = redisSessionDAO.getActiveSessions();
SysUserEntity sysUserEntity;
Object attribute = null;
for(Session sessionInfo : sessions){
//遍历Session,找到该用户名称对应的Session
attribute = sessionInfo.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
if (attribute == null) {
continue;
}
sysUserEntity = (SysUserEntity) ((SimplePrincipalCollection) attribute).getPrimaryPrincipal();
if (sysUserEntity == null) {
continue;
}
if (Objects.equals(sysUserEntity.getUsername(), username)) {
session=sessionInfo;
break;
}
}
if (session == null||attribute == null) {
return;
}
//删除session
if (isRemoveSession) {
redisSessionDAO.delete(session);
}
//删除Cache,在访问受限接口时会重新授权
DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
Authenticator authc = securityManager.getAuthenticator();
((LogoutAware) authc).onLogout((SimplePrincipalCollection) attribute);
}
}
package com.sh.demo.common.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* @Description Spring上下文工具类
* @Author Sans
* @CreateTime 2019/6/17 13:40
*/
@Component
public class SpringUtil implements ApplicationContextAware {
private static ApplicationContext context;
/**
* Spring在bean初始化后会判断是不是ApplicationContextAware的子类
* 如果该类是,setApplicationContext()方法,会将容器中ApplicationContext作为参数传入进去
* @Author Sans
* @CreateTime 2019/6/17 16:58
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
/**
* 通过Name返回指定的Bean
* @Author Sans
* @CreateTime 2019/6/17 16:03
*/
public static <T> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
}
三个controller类:
package com.sh.demo.controller;
import com.sh.demo.common.util.SHA256Util;
import com.sh.demo.common.util.ShiroUtils;
import com.sh.demo.core.entity.SysUserEntity;
import com.sh.demo.core.entity.SysUserRoleEntity;
import com.sh.demo.core.service.SysUserRoleService;
import com.sh.demo.core.service.SysUserService;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.*;
/**
* @Description 用户登录
* @Author Sans
* @CreateTime 2019/6/17 15:21
*/
@RestController
@RequestMapping("/userLogin")
public class UserLoginController {
@Autowired
private SysUserService sysUserService;
@Autowired
private SysUserRoleService sysUserRoleService;
/**
* 登录
* @Author Sans
* @CreateTime 2019/6/20 9:21
*/
@RequestMapping("/login")
public Map<String,Object> login(@RequestBody SysUserEntity sysUserEntity){
Map<String,Object> map = new HashMap<>();
//进行身份验证
try{
//验证身份和登陆
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(sysUserEntity.getUsername(), sysUserEntity.getPassword());
//进行登录操作
subject.login(token);
}catch (IncorrectCredentialsException e) {
map.put("code",500);
map.put("msg","用户不存在或者密码错误");
return map;
} catch (LockedAccountException e) {
map.put("code",500);
map.put("msg","登录失败,该用户已被冻结");
return map;
} catch (AuthenticationException e) {
map.put("code",500);
map.put("msg","该用户不存在");
return map;
} catch (Exception e) {
map.put("code",500);
map.put("msg","未知异常");
return map;
}
map.put("code",0);
map.put("msg","登录成功");
map.put("token",ShiroUtils.getSession().getId().toString());
return map;
}
/**
* 未登录
* @Author Sans
* @CreateTime 2019/6/20 9:22
*/
@RequestMapping("/unauth")
public Map<String,Object> unauth(){
Map<String,Object> map = new HashMap<>();
map.put("code",500);
map.put("msg","未登录");
return map;
}
/**
* 添加一个用户演示接口
* 这里仅作为演示不加任何权限和重复查询校验
* @Author Sans
* @CreateTime 2020/1/6 9:22
*/
@RequestMapping("/testAddUser")
public Map<String,Object> testAddUser(){
// 设置基础参数
SysUserEntity sysUser = new SysUserEntity();
sysUser.setUsername("user1");
sysUser.setState("NORMAL");
// 随机生成盐值
String salt = RandomStringUtils.randomAlphanumeric(20);
sysUser.setSalt(salt);
// 进行加密
String password ="123456";
sysUser.setPassword(SHA256Util.sha256(password, sysUser.getSalt()));
// 保存用户
sysUserService.save(sysUser);
// 保存角色
SysUserRoleEntity sysUserRoleEntity = new SysUserRoleEntity();
sysUserRoleEntity.setUserId(sysUser.getUserId()); // 保存用户完之后会把ID返回给用户实体
sysUserRoleService.save(sysUserRoleEntity);
// 返回结果
Map<String,Object> map = new HashMap<>();
map.put("code",0);
map.put("msg","添加成功");
return map;
}
}
package com.sh.demo.controller;
import com.sh.demo.common.util.ShiroUtils;
import com.sh.demo.core.entity.SysMenuEntity;
import com.sh.demo.core.entity.SysRoleEntity;
import com.sh.demo.core.entity.SysRoleMenuEntity;
import com.sh.demo.core.entity.SysUserEntity;
import com.sh.demo.core.service.SysMenuService;
import com.sh.demo.core.service.SysRoleMenuService;
import com.sh.demo.core.service.SysRoleService;
import com.sh.demo.core.service.SysUserService;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Description 权限测试
* @Author Sans
* @CreateTime 2019/6/19 11:38
*/
@RestController
@RequestMapping("/menu")
public class UserMenuController {
@Autowired
private SysUserService sysUserService;
@Autowired
private SysRoleService sysRoleService;
@Autowired
private SysMenuService sysMenuService;
@Autowired
private SysRoleMenuService sysRoleMenuService;
/**
* 获取用户信息集合
* @Author Sans
* @CreateTime 2019/6/19 10:36
* @Return Map<String,Object> 返回结果
*/
@RequestMapping("/getUserInfoList")
@RequiresPermissions("sys:user:info")
public Map<String,Object> getUserInfoList(){
Map<String,Object> map = new HashMap<>();
List<SysUserEntity> sysUserEntityList = sysUserService.list();
map.put("sysUserEntityList",sysUserEntityList);
return map;
}
/**
* 获取角色信息集合
* @Author Sans
* @CreateTime 2019/6/19 10:37
* @Return Map<String,Object> 返回结果
*/
@RequestMapping("/getRoleInfoList")
@RequiresPermissions("sys:role:info")
public Map<String,Object> getRoleInfoList(){
Map<String,Object> map = new HashMap<>();
List<SysRoleEntity> sysRoleEntityList = sysRoleService.list();
map.put("sysRoleEntityList",sysRoleEntityList);
return map;
}
/**
* 获取权限信息集合
* @Author Sans
* @CreateTime 2019/6/19 10:38
* @Return Map<String,Object>
*/
@RequestMapping("/getMenuInfoList")
@RequiresPermissions("sys:menu:info")
public Map<String,Object> getMenuInfoList(){
Map<String,Object> map = new HashMap<>();
List<SysMenuEntity> sysMenuEntityList = sysMenuService.list();
map.put("sysMenuEntityList",sysMenuEntityList);
return map;
}
/**
* 获取所有数据
* @Author Sans
* @CreateTime 2019/6/19 10:38
* @Return Map<String,Object>
*/
@RequestMapping("/getInfoAll")
@RequiresPermissions("sys:info:all")
public Map<String,Object> getInfoAll(){
Map<String,Object> map = new HashMap<>();
List<SysUserEntity> sysUserEntityList = sysUserService.list();
map.put("sysUserEntityList",sysUserEntityList);
List<SysRoleEntity> sysRoleEntityList = sysRoleService.list();
map.put("sysRoleEntityList",sysRoleEntityList);
List<SysMenuEntity> sysMenuEntityList = sysMenuService.list();
map.put("sysMenuEntityList",sysMenuEntityList);
return map;
}
/**
* 添加管理员角色权限(测试动态权限更新)
* @Author Sans
* @CreateTime 2019/6/19 10:39
* @Param username 用户ID
* @Return Map<String,Object>
*/
@RequestMapping("/addMenu")
public Map<String,Object> addMenu(){
//添加管理员角色权限
SysRoleMenuEntity sysRoleMenuEntity = new SysRoleMenuEntity();
sysRoleMenuEntity.setMenuId(4L);
sysRoleMenuEntity.setRoleId(1L);
sysRoleMenuService.save(sysRoleMenuEntity);
//清除缓存
String username = "admin";
ShiroUtils.deleteCache(username,false);
Map<String,Object> map = new HashMap<>();
map.put("code",200);
map.put("msg","权限添加成功");
return map;
}
}
package com.sh.demo.controller;
import com.sh.demo.common.util.ShiroUtils;
import com.sh.demo.core.service.SysMenuService;
import com.sh.demo.core.service.SysRoleMenuService;
import com.sh.demo.core.service.SysRoleService;
import com.sh.demo.core.service.SysUserService;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* @Description 角色测试
* @Author Sans
* @CreateTime 2019/6/19 11:38
*/
@RestController
@RequestMapping("/role")
public class UserRoleController {
@Autowired
private SysUserService sysUserService;
@Autowired
private SysRoleService sysRoleService;
@Autowired
private SysMenuService sysMenuService;
@Autowired
private SysRoleMenuService sysRoleMenuService;
/**
* 管理员角色测试接口
* @Author Sans
* @CreateTime 2019/6/19 10:38
* @Return Map<String,Object> 返回结果
*/
@RequestMapping("/getAdminInfo")
@RequiresRoles("ADMIN")
public Map<String,Object> getAdminInfo(){
Map<String,Object> map = new HashMap<>();
map.put("code",200);
map.put("msg","这里是只有管理员角色能访问的接口");
return map;
}
/**
* 用户角色测试接口
* @Author Sans
* @CreateTime 2019/6/19 10:38
* @Return Map<String,Object> 返回结果
*/
@RequestMapping("/getUserInfo")
@RequiresRoles("USER")
public Map<String,Object> getUserInfo(){
Map<String,Object> map = new HashMap<>();
map.put("code",200);
map.put("msg","这里是只有用户角色能访问的接口");
return map;
}
/**
* 角色测试接口
* @Author Sans
* @CreateTime 2019/6/19 10:38
* @Return Map<String,Object> 返回结果
*/
@RequestMapping("/getRoleInfo")
@RequiresRoles(value={"ADMIN","USER"},logical = Logical.OR)
@RequiresUser
public Map<String,Object> getRoleInfo(){
Map<String,Object> map = new HashMap<>();
map.put("code",200);
map.put("msg","这里是只要有ADMIN或者USER角色能访问的接口");
return map;
}
/**
* 登出
* @Author Sans
* @CreateTime 2019/6/19 10:38
* @Return Map<String,Object> 返回结果
*/
@RequestMapping("/getLogout")
@RequiresUser
public Map<String,Object> getLogout(){
//登出Shiro会帮我们清理掉Session和Cache
ShiroUtils.logout();
Map<String,Object> map = new HashMap<>();
map.put("code",200);
map.put("msg","登出");
return map;
}
}
接下来是dao层:
package com.sh.demo.core.dao;
import com.sh.demo.core.entity.SysMenuEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
/**
* @Description 权限DAO
* @Author Sans
* @CreateTime 2019/6/14 15:57
*/
public interface SysMenuDao extends BaseMapper<SysMenuEntity> {
/**
* 根据角色查询用户权限
* @Author Sans
* @CreateTime 2019/6/19 10:14
* @Param roleId 角色ID
* @Return List<SysMenuEntity> 权限集合
*/
List<SysMenuEntity> selectSysMenuByRoleId(Long roleId);
}
package com.sh.demo.core.dao;
import com.sh.demo.core.entity.SysRoleEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
/**
* @Description 角色DAO
* @Author Sans
* @CreateTime 2019/6/14 15:57
*/
public interface SysRoleDao extends BaseMapper<SysRoleEntity> {
/**
* 通过用户ID查询角色集合
* @Author Sans
* @CreateTime 2019/6/18 18:01
* @Param userId 用户ID
* @Return List<SysRoleEntity> 角色名集合
*/
List<SysRoleEntity> selectSysRoleByUserId(Long userId);
}
package com.sh.demo.core.dao;
import com.sh.demo.core.entity.SysRoleMenuEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @Description 角色权限关系DAO
* @Author Sans
* @CreateTime 2019/6/14 15:57
*/
public interface SysRoleMenuDao extends BaseMapper<SysRoleMenuEntity> {
}
package com.sh.demo.core.dao;
import com.sh.demo.core.entity.SysUserEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @Description 系统用户DAO
* @Author Sans
* @CreateTime 2019/6/14 15:57
*/
public interface SysUserDao extends BaseMapper<SysUserEntity> {
}
package com.sh.demo.core.dao;
import com.sh.demo.core.entity.SysUserRoleEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @Description 用户与角色关系DAO
* @Author Sans
* @CreateTime 2019/6/14 15:57
*/
public interface SysUserRoleDao extends BaseMapper<SysUserRoleEntity> {
}
所有的实体类:
package com.sh.demo.core.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
* @Description 权限实体
* @Author Sans
* @CreateTime 2019/6/14 15:57
*/
@Data
@TableName("sys_menu")
public class SysMenuEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 权限ID
*/
@TableId
private Long menuId;
/**
* 权限名称
*/
private String name;
/**
* 权限标识
*/
private String perms;
}
package com.sh.demo.core.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
* @Description 角色实体
* @Author Sans
* @CreateTime 2019/6/14 15:57
*/
@Data
@TableName("sys_role")
public class SysRoleEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 角色ID
*/
@TableId
private Long roleId;
/**
* 角色名称
*/
private String roleName;
}
package com.sh.demo.core.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import lombok.Data;
/**
* @Description 角色与权限关系实体
* @Author Sans
* @CreateTime 2019/6/14 15:57
*/
@Data
@TableName("sys_role_menu")
public class SysRoleMenuEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@TableId
private Long id;
/**
* 角色ID
*/
private Long roleId;
/**
* 权限ID
*/
private Long menuId;
}
package com.sh.demo.core.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
* @Description 系统用户实体
* @Author Sans
* @CreateTime 2019/6/14 15:57
*/
@Data
@TableName("sys_user")
public class SysUserEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 用户ID
*/
@TableId
private Long userId;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 盐值
*/
private String salt;
/**
* 状态:NORMAL正常 PROHIBIT禁用
*/
private String state;
}
package com.sh.demo.core.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import lombok.Data;
/**
* @Description 用户与角色关系实体
* @Author Sans
* @CreateTime 2019/6/14 15:57
*/
@Data
@TableName("sys_user_role")
public class SysUserRoleEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@TableId
private Long id;
/**
* 用户ID
*/
private Long userId;
/**
* 角色ID
*/
private Long roleId;
}
所有的service:
package com.sh.demo.core.service.impl;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sh.demo.core.dao.SysMenuDao;
import com.sh.demo.core.entity.SysMenuEntity;
import com.sh.demo.core.service.SysMenuService;
import java.util.List;
/**
* @Description 权限业务实现
* @Author Sans
* @CreateTime 2019/6/14 15:57
*/
@Service("sysMenuService")
public class SysMenuServiceImpl extends ServiceImpl<SysMenuDao, SysMenuEntity> implements SysMenuService {
/**
* 根据角色查询用户权限
* @Author Sans
* @CreateTime 2019/6/19 10:14
* @Param roleId 角色ID
* @Return List<SysMenuEntity> 权限集合
*/
@Override
public List<SysMenuEntity> selectSysMenuByRoleId(Long roleId) {
return this.baseMapper.selectSysMenuByRoleId(roleId);
}
}
package com.sh.demo.core.service.impl;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sh.demo.core.dao.SysRoleMenuDao;
import com.sh.demo.core.entity.SysRoleMenuEntity;
import com.sh.demo.core.service.SysRoleMenuService;
/**
* @Description 角色与权限业务实现
* @Author Sans
* @CreateTime 2019/6/14 15:57
*/
@Service("sysRoleMenuService")
public class SysRoleMenuServiceImpl extends ServiceImpl<SysRoleMenuDao, SysRoleMenuEntity> implements SysRoleMenuService {
}
package com.sh.demo.core.service.impl;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sh.demo.core.dao.SysRoleDao;
import com.sh.demo.core.entity.SysRoleEntity;
import com.sh.demo.core.service.SysRoleService;
import java.util.List;
/**
* @Description 角色业务实现
* @Author Sans
* @CreateTime 2019/6/14 15:57
*/
@Service("sysRoleService")
public class SysRoleServiceImpl extends ServiceImpl<SysRoleDao, SysRoleEntity> implements SysRoleService {
/**
* 通过用户ID查询角色集合
* @Author Sans
* @CreateTime 2019/6/18 18:01
* @Param userId 用户ID
* @Return List<SysRoleEntity> 角色名集合
*/
@Override
public List<SysRoleEntity> selectSysRoleByUserId(Long userId) {
return this.baseMapper.selectSysRoleByUserId(userId);
}
}
package com.sh.demo.core.service.impl;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sh.demo.core.dao.SysUserRoleDao;
import com.sh.demo.core.entity.SysUserRoleEntity;
import com.sh.demo.core.service.SysUserRoleService;
/**
* @Description 用户与角色业务实现
* @Author Sans
* @CreateTime 2019/6/14 15:57
*/
@Service("sysUserRoleService")
public class SysUserRoleServiceImpl extends ServiceImpl<SysUserRoleDao, SysUserRoleEntity> implements SysUserRoleService {
}
package com.sh.demo.core.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sh.demo.core.dao.SysUserDao;
import com.sh.demo.core.entity.SysUserEntity;
import com.sh.demo.core.service.SysUserService;
/**
* @Description 系统用户业务实现
* @Author Sans
* @CreateTime 2019/6/14 15:57
*/
@Service("sysUserService")
public class SysUserServiceImpl extends ServiceImpl<SysUserDao, SysUserEntity> implements SysUserService {
/**
* 根据用户名查询实体
* @Author Sans
* @CreateTime 2019/6/14 16:30
* @Param username 用户名
* @Return SysUserEntity 用户实体
*/
@Override
public SysUserEntity selectUserByName(String username) {
QueryWrapper<SysUserEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(SysUserEntity::getUsername,username);
SysUserEntity selectOne = this.baseMapper.selectOne(queryWrapper);
return selectOne;
}
}
所有的xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sh.demo.core.dao.SysMenuDao">
<!-- 可根据自己的需求,是否要使用 -->
<resultMap type="com.sh.demo.core.entity.SysMenuEntity" id="sysMenuMap">
<result property="menuId" column="menu_id"/>
<result property="parentId" column="parent_id"/>
<result property="name" column="name"/>
<result property="url" column="url"/>
<result property="perms" column="perms"/>
<result property="type" column="type"/>
<result property="icon" column="icon"/>
<result property="createTime" column="create_time"/>
</resultMap>
<!-- 查询用户权限集合 -->
<select id="selectSysMenuByRoleId" parameterType="long" resultType="com.sh.demo.core.entity.SysMenuEntity" >
SELECT sm.* FROM sys_menu sm
LEFT JOIN sys_role_menu se ON sm.menu_id = se.menu_id
WHERE se.role_id = #{roleId}
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sh.demo.core.dao.SysRoleDao">
<!-- 可根据自己的需求,是否要使用 -->
<resultMap type="com.sh.demo.core.entity.SysRoleEntity" id="sysRoleMap">
<result property="roleId" column="role_id"/>
<result property="roleName" column="role_name"/>
<result property="remark" column="remark"/>
<result property="createTime" column="create_time"/>
</resultMap>
<!-- 查询用户角色集合 -->
<select id="selectSysRoleByUserId" parameterType="long" resultType="com.sh.demo.core.entity.SysRoleEntity" >
SELECT sr.* FROM sys_role sr
LEFT JOIN sys_user_role se ON sr.role_id=se.role_id
WHERE se.user_id = #{userId}
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sh.demo.core.dao.SysRoleMenuDao">
<!-- 可根据自己的需求,是否要使用 -->
<resultMap type="com.sh.demo.core.entity.SysRoleMenuEntity" id="sysRoleMenuMap">
<result property="id" column="id"/>
<result property="roleId" column="role_id"/>
<result property="menuId" column="menu_id"/>
</resultMap>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sh.demo.core.dao.SysUserDao">
<!-- 可根据自己的需求,是否要使用 -->
<resultMap type="com.sh.demo.core.entity.SysUserEntity" id="sysUserMap">
<result property="userId" column="user_id"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
<result property="salt" column="salt"/>
<result property="email" column="email"/>
<result property="mobile" column="mobile"/>
<result property="img" column="img"/>
<result property="intro" column="intro"/>
<result property="deptId" column="dept_id"/>
<result property="status" column="status"/>
<result property="createTime" column="create_time"/>
<result property="createUser" column="create_user"/>
<result property="modifyTime" column="modify_time"/>
<result property="modifyUser" column="modify_user"/>
</resultMap>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sh.demo.core.dao.SysUserRoleDao">
<!-- 可根据自己的需求,是否要使用 -->
<resultMap type="com.sh.demo.core.entity.SysUserRoleEntity" id="sysUserRoleMap">
<result property="id" column="id"/>
<result property="userId" column="user_id"/>
<result property="roleId" column="role_id"/>
</resultMap>
</mapper>
yml文件:
# 配置端口
server:
port: 8764
spring:
# 配置数据源
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/shiro?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false
username: root
password: 123456
type: com.alibaba.druid.pool.DruidDataSource
# Redis数据源
redis:
host: 127.0.0.1
port: 6379
timeout: 6000
password: 123456
jedis:
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 5 # 连接池中的最小空闲连接
# mybatis-plus相关配置
mybatis-plus:
# xml扫描,多个目录用逗号或者分号分隔(告诉 Mapper 所对应的 XML 文件位置)
mapper-locations: classpath:mapper/*.xml
# 以下配置均有默认值,可以不设置
global-config:
db-config:
#主键类型 AUTO:"数据库ID自增" INPUT:"用户输入ID",ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
id-type: auto
#字段策略 IGNORED:"忽略判断" NOT_NULL:"非 NULL 判断") NOT_EMPTY:"非空判断"
field-strategy: NOT_EMPTY
#数据库类型
db-type: MYSQL
configuration:
# 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
map-underscore-to-camel-case: true
# 返回map时true:当查询数据为空时字段返回为null,false:不加这个查询数据为空时,字段将被隐藏
call-setters-on-nulls: true
# 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
pom.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sh</groupId>
<artifactId>spring-boot-shiro-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-shiro-demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- AOP依赖,一定要加,否则权限拦截验证不生效 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- lombok插件 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<!-- mybatisPlus 核心库 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
<!-- 引入阿里数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.6</version>
</dependency>
<!-- Shiro 核心依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!-- Shiro-redis插件 -->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>3.1.0</version>
</dependency>
<!-- StringUtilS工具 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
</dependency>
<!-- json 转换工具 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
文章最后,附上sql语句吧:
/*
Navicat MySQL Data Transfer
Source Server : 我的腾讯云
Source Server Type : MySQL
Source Server Version : 50725
Source Host : 140.143.244.170:3306
Source Schema : my_shiro
Target Server Type : MySQL
Target Server Version : 50725
File Encoding : 65001
Date: 20/06/2019 11:05:03
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for sys_menu
-- ----------------------------
DROP TABLE IF EXISTS `sys_menu`;
CREATE TABLE `sys_menu` (
`menu_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '权限ID',
`name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限名称',
`perms` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限标识',
PRIMARY KEY (`menu_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '权限表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_menu
-- ----------------------------
INSERT INTO `sys_menu` VALUES (1, '查看用户列表', 'sys:user:info');
INSERT INTO `sys_menu` VALUES (2, '查看角色列表', 'sys:role:info');
INSERT INTO `sys_menu` VALUES (3, '查看权限列表', 'sys:menu:info');
INSERT INTO `sys_menu` VALUES (4, '查看所有数据', 'sys:info:all');
-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`role_id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '角色ID',
`role_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色名称',
PRIMARY KEY (`role_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES (1, 'ADMIN');
INSERT INTO `sys_role` VALUES (2, 'USER');
-- ----------------------------
-- Table structure for sys_role_menu
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_menu`;
CREATE TABLE `sys_role_menu` (
`id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`role_id` bigint(11) NULL DEFAULT NULL COMMENT '角色ID',
`menu_id` bigint(11) NULL DEFAULT NULL COMMENT '权限ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色与权限关系表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_role_menu
-- ----------------------------
INSERT INTO `sys_role_menu` VALUES (1, 1, 1);
INSERT INTO `sys_role_menu` VALUES (2, 1, 2);
INSERT INTO `sys_role_menu` VALUES (3, 1, 3);
INSERT INTO `sys_role_menu` VALUES (4, 2, 1);
-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`user_id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名',
`password` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码',
`salt` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '盐值',
`state` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '状态:NORMAL正常 PROHIBIT禁用',
PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统用户表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (1, 'admin', 'a1bb09ad5dea12e0f94762cb116c447e80c784d8aa2c6625263f7f3436cdd583', 'RvP3UID2n30Q2sycZYvH', 'NORMAL');
INSERT INTO `sys_user` VALUES (2, 'user', '376eb5d2698c804ee83594fe8b0217f03ad138a046f7fa42b44c232c2e5e2b38', 'OVlrD37bDUKNcFRB10qG', 'NORMAL');
-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
`id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`user_id` bigint(11) NULL DEFAULT NULL COMMENT '用户ID',
`role_id` bigint(11) NULL DEFAULT NULL COMMENT '角色ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户与角色关系表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES (1, 1, 1);
INSERT INTO `sys_user_role` VALUES (2, 2, 2);
SET FOREIGN_KEY_CHECKS = 1;