2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > SpringBoot 整合Shiro实现动态权限加载更新 Session共享 单点登录

SpringBoot 整合Shiro实现动态权限加载更新 Session共享 单点登录

时间:2018-10-02 01:10:30

相关推荐

SpringBoot 整合Shiro实现动态权限加载更新 Session共享 单点登录

你知道的越多,不知道的就越多,业余的像一棵小草!

你来,我们一起精进!你不来,我和你的竞争对手一起精进!

编辑:业余草

推荐:/?p=5059

一.说明

Shiro是一个安全框架,项目中主要用它做认证,授权,加密,以及用户的会话管理,虽然Shiro没有SpringSecurity功能更丰富,但是它轻量,简单,在项目中通常业务需求Shiro也都能胜任.二.项目环境

MyBatis-Plus版本: 3.1.0

SpringBoot版本:2.1.5

JDK版本:1.8

Shiro版本:1.4

Shiro-redis插件版本:3.1.0

数据表(SQL文件在项目中):数据库中测试号的密码进行了加密,密码皆为123456

Maven依赖如下:<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>

<!--StringUitlS工具-->

<dependency>

<groupId>mons</groupId>

<artifactId>commons-lang3</artifactId>

<version>3.5</version>

</dependency>

</dependencies>

配置如下:#配置端口

server:

port:8764

spring:

#配置数据源

datasource:

driver-class-name:com.mysql.cj.jdbc.Driver

url:jdbc:mysql://localhost:3306/my_shiro?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false

username:root

password:root

type:com.alibaba.druid.pool.DruidDataSource

#Redis数据源

redis:

host:localhost

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:"全局唯一IDUUID";

id-type:auto

#字段策略IGNORED:"忽略判断"NOT_NULL:"非NULL判断")NOT_EMPTY:"非空判断"

field-strategy:NOT_EMPTY

#数据库类型

db-type:MYSQL

configuration:

#是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射

map-underscore-to-camel-case:true

#如果查询结果中包含空值的列,则MyBatis在映射的时候,不会映射这个字段

call-setters-on-nulls:true

#这个配置会将执行的sql打印出来,在开发或测试的时候可以用

log-impl:org.apache.ibatis.logging.stdout.StdOutImpl

二.编写项目基础类

用户实体,Dao,Service等在这里省略,请参考源码编写Exception类来处理Shiro权限拦截异常

创建SHA256Util加密工具

创建Spring工具/**

*@DescriptionSpring上下文工具类

*@AuthorSans

*@CreateTime/6/1713:40

*/

@Component

publicclassSpringUtilimplementsApplicationContextAware{

privatestaticApplicationContextcontext;

/**

*Spring在bean初始化后会判断是不是ApplicationContextAware的子类

*如果该类是,setApplicationContext()方法,会将容器中ApplicationContext作为参数传入进去

*@AuthorSans

*@CreateTime/6/1716:58

*/

@Override

publicvoidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException{

context=applicationContext;

}

/**

*通过Name返回指定的Bean

*@AuthorSans

*@CreateTime/6/1716:03

*/

publicstatic<T>TgetBean(Class<T>beanClass){

returncontext.getBean(beanClass);

}

}

创建Shiro工具/**

*@DescriptionShiro工具类

*@AuthorSans

*@CreateTime/6/1516:11

*/

publicclassShiroUtils{

/**私有构造器**/

privateShiroUtils(){}

privatestaticRedisSessionDAOredisSessionDAO=SpringUtil.getBean(RedisSessionDAO.class);

/**

*获取当前用户Session

*@AuthorSans

*@CreateTime/6/1717:03

*@ReturnSysUserEntity用户信息

*/

publicstaticSessiongetSession(){

returnSecurityUtils.getSubject().getSession();

}

/**

*用户登出

*@AuthorSans

*@CreateTime/6/1717:23

*/

publicstaticvoidlogout(){

SecurityUtils.getSubject().logout();

}

/**

*获取当前用户信息

*@AuthorSans

*@CreateTime/6/1717:03

*@ReturnSysUserEntity用户信息

*/

publicstaticSysUserEntitygetUserInfo(){

return(SysUserEntity)SecurityUtils.getSubject().getPrincipal();

}

/**

*删除用户缓存信息

*@AuthorSans

*@CreateTime/6/1713:57

*@Paramusername用户名称

*@ParamisRemoveSession是否删除Session

*@Returnvoid

*/

publicstaticvoiddeleteCache(Stringusername,booleanisRemoveSession){

//从缓存中获取Session

Sessionsession=null;

Collection<Session>sessions=redisSessionDAO.getActiveSessions();

SysUserEntitysysUserEntity;

Objectattribute=null;

for(SessionsessionInfo: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;

}

}

if(session==null||attribute==null){

return;

}

//删除session

if(isRemoveSession){

redisSessionDAO.delete(session);

}

//删除Cache,在访问受限接口时会重新授权

DefaultWebSecurityManagersecurityManager=(DefaultWebSecurityManager)SecurityUtils.getSecurityManager();

Authenticatorauthc=securityManager.getAuthenticator();

((LogoutAware)authc).onLogout((SimplePrincipalCollection)attribute);

}

}

创建Shiro的SessionId生成器

三.编写Shiro核心类

创建Realm用于授权和认证/**

*@DescriptionShiro权限匹配和账号密码匹配

*@AuthorSans

*@CreateTime/6/1511:27

*/

publicclassShiroRealmextendsAuthorizingRealm{

@Autowired

privateSysUserServicesysUserService;

@Autowired

privateSysRoleServicesysRoleService;

@Autowired

privateSysMenuServicesysMenuService;

/**

*授权权限

*用户进行权限验证时候Shiro会去缓存中找,如果查不到数据,会执行这个方法去查权限,并放入缓存中

*@AuthorSans

*@CreateTime/6/1211:44

*/

@Override

protectedAuthorizationInfodoGetAuthorizationInfo(PrincipalCollectionprincipalCollection){

SimpleAuthorizationInfoauthorizationInfo=newSimpleAuthorizationInfo();

SysUserEntitysysUserEntity=(SysUserEntity)principalCollection.getPrimaryPrincipal();

//获取用户ID

LonguserId=sysUserEntity.getUserId();

//这里可以进行授权和处理

Set<String>rolesSet=newHashSet<>();

Set<String>permsSet=newHashSet<>();

//查询角色和权限(这里根据业务自行查询)

List<SysRoleEntity>sysRoleEntityList=sysRoleService.selectSysRoleByUserId(userId);

for(SysRoleEntitysysRoleEntity:sysRoleEntityList){

rolesSet.add(sysRoleEntity.getRoleName());

List<SysMenuEntity>sysMenuEntityList=sysMenuService.selectSysMenuByRoleId(sysRoleEntity.getRoleId());

for(SysMenuEntitysysMenuEntity:sysMenuEntityList){

permsSet.add(sysMenuEntity.getPerms());

}

}

//将查到的权限和角色分别传入authorizationInfo中

authorizationInfo.setStringPermissions(permsSet);

authorizationInfo.setRoles(rolesSet);

returnauthorizationInfo;

}

/**

*身份认证

*@AuthorSans

*@CreateTime/6/1212:36

*/

@Override

protectedAuthenticationInfodoGetAuthenticationInfo(AuthenticationTokenauthenticationToken)throwsAuthenticationException{

//获取用户的输入的账号.

Stringusername=(String)authenticationToken.getPrincipal();

//通过username从数据库中查找User对象,如果找到进行验证

//实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法

SysUserEntityuser=sysUserService.selectUserByName(username);

//判断账号是否存在

if(user==null){

thrownewAuthenticationException();

}

//判断账号是否被冻结

if(user.getState()==null||user.getState().equals("PROHIBIT")){

thrownewLockedAccountException();

}

//进行验证

SimpleAuthenticationInfoauthenticationInfo=newSimpleAuthenticationInfo(

user,//用户名

user.getPassword(),//密码

ByteSource.Util.bytes(user.getSalt()),//设置盐值

getName()

);

//验证成功开始踢人(清除缓存和Session)

ShiroUtils.deleteCache(username,true);

returnauthenticationInfo;

}

}

创建SessionManager类

创建ShiroConfig配置类/**

*@DescriptionShiro配置类

*@AuthorSans

*@CreateTime/6/1017:42

*/

@Configuration

publicclassShiroConfig{

privatefinalStringCACHE_KEY="shiro:cache:";

privatefinalStringSESSION_KEY="shiro:session:";

privatefinalintEXPIRE=1800;

//Redis配置

@Value("${spring.redis.host}")

privateStringhost;

@Value("${spring.redis.port}")

privateintport;

@Value("${spring.redis.timeout}")

privateinttimeout;

@Value("${spring.redis.password}")

privateStringpassword;

/**

*开启Shiro-aop注解支持

*@Attention使用代理方式所以需要开启代码支持

*@AuthorSans

*@CreateTime/6/128:38

*/

@Bean

publicAuthorizationAttributeSourceAdvisorauthorizationAttributeSourceAdvisor(SecurityManagersecurityManager){

AuthorizationAttributeSourceAdvisorauthorizationAttributeSourceAdvisor=newAuthorizationAttributeSourceAdvisor();

authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);

returnauthorizationAttributeSourceAdvisor;

}

/**

*Shiro基础配置

*@AuthorSans

*@CreateTime/6/128:42

*/

@Bean

publicShiroFilterFactoryBeanshiroFilterFactory(SecurityManagersecurityManager){

ShiroFilterFactoryBeanshiroFilterFactoryBean=newShiroFilterFactoryBean();

shiroFilterFactoryBean.setSecurityManager(securityManager);

Map<String,String>filterChainDefinitionMap=newLinkedHashMap<>();

//注意过滤器配置顺序不能颠倒

//配置过滤:不会被拦截的链接

filterChainDefinitionMap.put("/static/**","anon");

filterChainDefinitionMap.put("/userLogin/**","anon");

filterChainDefinitionMap.put("/**","authc");

//配置shiro默认登录界面地址,前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据

shiroFilterFactoryBean.setLoginUrl("/userLogin/unauth");

shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

returnshiroFilterFactoryBean;

}

/**

*安全管理器

*@AuthorSans

*@CreateTime/6/1210:34

*/

@Bean

publicSecurityManagersecurityManager(){

DefaultWebSecurityManagersecurityManager=newDefaultWebSecurityManager();

//自定义Ssession管理

securityManager.setSessionManager(sessionManager());

//自定义Cache实现

securityManager.setCacheManager(cacheManager());

//自定义Realm验证

securityManager.setRealm(shiroRealm());

returnsecurityManager;

}

/**

*身份验证器

*@AuthorSans

*@CreateTime/6/1210:37

*/

@Bean

publicShiroRealmshiroRealm(){

ShiroRealmshiroRealm=newShiroRealm();

shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());

returnshiroRealm;

}

/**

*凭证匹配器

*将密码校验交给Shiro的SimpleAuthenticationInfo进行处理,在这里做匹配配置

*@AuthorSans

*@CreateTime/6/1210:48

*/

@Bean

publicHashedCredentialsMatcherhashedCredentialsMatcher(){

HashedCredentialsMatchershaCredentialsMatcher=newHashedCredentialsMatcher();

//散列算法:这里使用SHA256算法;

shaCredentialsMatcher.setHashAlgorithmName(SHA256Util.HASH_ALGORITHM_NAME);

//散列的次数,比如散列两次,相当于md5(md5(""));

shaCredentialsMatcher.setHashIterations(SHA256Util.HASH_ITERATIONS);

returnshaCredentialsMatcher;

}

/**

*配置Redis管理器

*@Attention使用的是shiro-redis开源插件

*@AuthorSans

*@CreateTime/6/1211:06

*/

@Bean

publicRedisManagerredisManager(){

RedisManagerredisManager=newRedisManager();

redisManager.setHost(host);

redisManager.setPort(port);

redisManager.setTimeout(timeout);

redisManager.setPassword(password);

returnredisManager;

}

/**

*配置Cache管理器

*用于往Redis存储权限和角色标识

*@Attention使用的是shiro-redis开源插件

*@AuthorSans

*@CreateTime/6/1212:37

*/

@Bean

publicRedisCacheManagercacheManager(){

RedisCacheManagerredisCacheManager=newRedisCacheManager();

redisCacheManager.setRedisManager(redisManager());

redisCacheManager.setKeyPrefix(CACHE_KEY);

//配置缓存的话要求放在session里面的实体类必须有个id标识

redisCacheManager.setPrincipalIdFieldName("userId");

returnredisCacheManager;

}

/**

*SessionID生成器

*@AuthorSans

*@CreateTime/6/1213:12

*/

@Bean

publicShiroSessionIdGeneratorsessionIdGenerator(){

returnnewShiroSessionIdGenerator();

}

/**

*配置RedisSessionDAO

*@Attention使用的是shiro-redis开源插件

*@AuthorSans

*@CreateTime/6/1213:44

*/

@Bean

publicRedisSessionDAOredisSessionDAO(){

RedisSessionDAOredisSessionDAO=newRedisSessionDAO();

redisSessionDAO.setRedisManager(redisManager());

redisSessionDAO.setSessionIdGenerator(sessionIdGenerator());

redisSessionDAO.setKeyPrefix(SESSION_KEY);

redisSessionDAO.setExpire(expire);

returnredisSessionDAO;

}

/**

*配置Session管理器

*@AuthorSans

*@CreateTime/6/1214:25

*/

@Bean

publicSessionManagersessionManager(){

ShiroSessionManagershiroSessionManager=newShiroSessionManager();

shiroSessionManager.setSessionDAO(redisSessionDAO());

returnshiroSessionManager;

}

}

四.实现权限控制

Shiro可以用代码或者注解来控制权限,通常我们使用注解控制,不仅简单方便,而且更加灵活.Shiro注解一共有五个:

一般情况下我们在项目中做权限控制,使用最多的是RequiresPermissions和RequiresRoles,允许存在多个角色和权限,默认逻辑是AND,也就是同时拥有这些才可以访问方法,可以在注解中以参数的形式设置成OR示例

使用顺序:Shiro注解是存在顺序的,当多个注解在一个方法上的时候,会逐个检查,知道全部通过为止,默认拦截顺序是:RequiresRoles->RequiresPermissions->RequiresAuthentication->

RequiresUser->RequiresGuest示例

创建UserRoleController角色拦截测试类/**

*@Description角色测试

*@AuthorSans

*@CreateTime/6/1911:38

*/

@RestController

@RequestMapping("/role")

publicclassUserRoleController{

@Autowired

privateSysUserServicesysUserService;

@Autowired

privateSysRoleServicesysRoleService;

@Autowired

privateSysMenuServicesysMenuService;

@Autowired

privateSysRoleMenuServicesysRoleMenuService;

/**

*管理员角色测试接口

*@AuthorSans

*@CreateTime/6/1910:38

*@ReturnMap<String,Object>返回结果

*/

@RequestMapping("/getAdminInfo")

@RequiresRoles("ADMIN")

publicMap<String,Object>getAdminInfo(){

Map<String,Object>map=newHashMap<>();

map.put("code",200);

map.put("msg","这里是只有管理员角色能访问的接口");

returnmap;

}

/**

*用户角色测试接口

*@AuthorSans

*@CreateTime/6/1910:38

*@ReturnMap<String,Object>返回结果

*/

@RequestMapping("/getUserInfo")

@RequiresRoles("USER")

publicMap<String,Object>getUserInfo(){

Map<String,Object>map=newHashMap<>();

map.put("code",200);

map.put("msg","这里是只有用户角色能访问的接口");

returnmap;

}

/**

*角色测试接口

*@AuthorSans

*@CreateTime/6/1910:38

*@ReturnMap<String,Object>返回结果

*/

@RequestMapping("/getRoleInfo")

@RequiresRoles(value={"ADMIN","USER"},logical=Logical.OR)

@RequiresUser

publicMap<String,Object>getRoleInfo(){

Map<String,Object>map=newHashMap<>();

map.put("code",200);

map.put("msg","这里是只要有ADMIN或者USER角色能访问的接口");

returnmap;

}

/**

*登出(测试登出)

*@AuthorSans

*@CreateTime/6/1910:38

*@ReturnMap<String,Object>返回结果

*/

@RequestMapping("/getLogout")

@RequiresUser

publicMap<String,Object>getLogout(){

ShiroUtils.logout();

Map<String,Object>map=newHashMap<>();

map.put("code",200);

map.put("msg","登出");

returnmap;

}

}

创建UserMenuController权限拦截测试类/**

*@Description权限测试

*@AuthorSans

*@CreateTime/6/1911:38

*/

@RestController

@RequestMapping("/menu")

publicclassUserMenuController{

@Autowired

privateSysUserServicesysUserService;

@Autowired

privateSysRoleServicesysRoleService;

@Autowired

privateSysMenuServicesysMenuService;

@Autowired

privateSysRoleMenuServicesysRoleMenuService;

/**

*获取用户信息集合

*@AuthorSans

*@CreateTime/6/1910:36

*@ReturnMap<String,Object>返回结果

*/

@RequestMapping("/getUserInfoList")

@RequiresPermissions("sys:user:info")

publicMap<String,Object>getUserInfoList(){

Map<String,Object>map=newHashMap<>();

List<SysUserEntity>sysUserEntityList=sysUserService.list();

map.put("sysUserEntityList",sysUserEntityList);

returnmap;

}

/**

*获取角色信息集合

*@AuthorSans

*@CreateTime/6/1910:37

*@ReturnMap<String,Object>返回结果

*/

@RequestMapping("/getRoleInfoList")

@RequiresPermissions("sys:role:info")

publicMap<String,Object>getRoleInfoList(){

Map<String,Object>map=newHashMap<>();

List<SysRoleEntity>sysRoleEntityList=sysRoleService.list();

map.put("sysRoleEntityList",sysRoleEntityList);

returnmap;

}

/**

*获取权限信息集合

*@AuthorSans

*@CreateTime/6/1910:38

*@ReturnMap<String,Object>返回结果

*/

@RequestMapping("/getMenuInfoList")

@RequiresPermissions("sys:menu:info")

publicMap<String,Object>getMenuInfoList(){

Map<String,Object>map=newHashMap<>();

List<SysMenuEntity>sysMenuEntityList=sysMenuService.list();

map.put("sysMenuEntityList",sysMenuEntityList);

returnmap;

}

/**

*获取所有数据

*@AuthorSans

*@CreateTime/6/1910:38

*@ReturnMap<String,Object>返回结果

*/

@RequestMapping("/getInfoAll")

@RequiresPermissions("sys:info:all")

publicMap<String,Object>getInfoAll(){

Map<String,Object>map=newHashMap<>();

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

returnmap;

}

/**

*添加管理员角色权限(测试动态权限更新)

*@AuthorSans

*@CreateTime/6/1910:39

*@Paramusername用户ID

*@ReturnMap<String,Object>返回结果

*/

@RequestMapping("/addMenu")

publicMap<String,Object>addMenu(){

//添加管理员角色权限

SysRoleMenuEntitysysRoleMenuEntity=newSysRoleMenuEntity();

sysRoleMenuEntity.setMenuId(4L);

sysRoleMenuEntity.setRoleId(1L);

sysRoleMenuService.save(sysRoleMenuEntity);

//清除缓存

Stringusername="admin";

ShiroUtils.deleteCache(username,false);

Map<String,Object>map=newHashMap<>();

map.put("code",200);

map.put("msg","权限添加成功");

returnmap;

}

}

创建UserLoginController登录类/**

*@Description用户登录

*@AuthorSans

*@CreateTime/6/1715:21

*/

@RestController

@RequestMapping("/userLogin")

publicclassUserLoginController{

@Autowired

privateSysUserServicesysUserService;

/**

*登录

*@AuthorSans

*@CreateTime/6/209:21

*/

@RequestMapping("/login")

publicMap<String,Object>login(@RequestBodySysUserEntitysysUserEntity){

Map<String,Object>map=newHashMap<>();

//进行身份验证

try{

//验证身份和登陆

Subjectsubject=SecurityUtils.getSubject();

UsernamePasswordTokentoken=newUsernamePasswordToken(sysUserEntity.getUsername(),sysUserEntity.getPassword());

//验证成功进行登录操作

subject.login(token);

}catch(IncorrectCredentialsExceptione){

map.put("code",500);

map.put("msg","用户不存在或者密码错误");

returnmap;

}catch(LockedAccountExceptione){

map.put("code",500);

map.put("msg","登录失败,该用户已被冻结");

returnmap;

}catch(AuthenticationExceptione){

map.put("code",500);

map.put("msg","该用户不存在");

returnmap;

}catch(Exceptione){

map.put("code",500);

map.put("msg","未知异常");

returnmap;

}

map.put("code",0);

map.put("msg","登录成功");

map.put("token",ShiroUtils.getSession().getId().toString());

returnmap;

}

/**

*未登录

*@AuthorSans

*@CreateTime/6/209:22

*/

@RequestMapping("/unauth")

publicMap<String,Object>unauth(){

Map<String,Object>map=newHashMap<>();

map.put("code",500);

map.put("msg","未登录");

returnmap;

}

}

五.POSTMAN测试

登录成功后会返回TOKEN,因为是单点登录,再次登陆的话会返回新的TOKEN,之前Redis的TOKEN就会失效了

当第一次访问接口后我们可以看到缓存中已经有权限数据了,在次访问接口的时候,Shiro会直接去缓存中拿取权限,注意访问接口时候要设置请求头.

ADMIN这个号现在没有sys:info:all这个权限的,所以无法访问getInfoAll接口,我们要动态分配权限后,要清掉缓存,在访问接口时候,Shiro会去重新执行授权方法,之后再次把权限和角色数据放入缓存中

访问添加权限测试接口,因为是测试,我把增加权限的用户ADMIN写死在里面了,权限添加后,调用工具类清掉缓存,我们可以发现,Redis中已经没有缓存了

再次访问getInfoAll接口,因为缓存中没有数据,Shiro会重新授权查询权限,拦截通过

六.项目源码

/liselotte/spring-boot-shiro-demo

/xuyulong/my-java-demo

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。