上一篇博客 SpringSecurity 实战项目(三)——动态管理Restful风格权限+JWT+单点登录它支持restful
风格的接口权限管理,也可以区分客户端的请求方式。
本片博客添加了redis,本篇博客将在SpringSecurity 实战项目(三)——动态管理Restful风格权限+JWT+单点登录的基础上进行修改使其支持redis
的身份管理。
源码地址:
源码地址:https://gitee.com/zenghua3300/SpringSecurity
喜欢的小伙伴麻烦帮点一个star
如果是刚接触security
的小伙伴,可以先看下这两篇基础博客
security认证过程:
security授权过程:
JWT全面解读、详细使用步骤:
重要
本文设计和代码是基于 以下博客(请点击)
SpringSecurity 实战项目(三)——动态管理Restful风格权限+JWT
进行修改。
一、分析
redis
称为缓存数据库主要作用之一就是减少数据库读压力,所以我们要在项目中操作数据库的地方用redis
,在这个项目中在登录的时候,查询用户信息并获取用户信息,接着获取用户权限,这两个地方需要去数据库查数据,我们可以在这两个地方加上redis
,当用户登录的时候,先去redis
查看有没有该用户的信息,如果有就用redis
里边的数据进行登录,如果没有则进行进行登录流程,最后把用户数据存入redis
里边,下次登录的时候就可以走redis
。- 我们项目中登录之后会生成一个
Token
,我们就把这个Token
存入redis
里边,这个Token
里边有用户名,密码,权限
,所以我们要在项目中处理这个Token
,Token
是json
格式的,要从json
转换成实体对象,然后交给security
进行验证,转换的过程看似简单,实际做起来会发现有一些坑,太过细节的东西我这里就不说了,有兴趣的小伙伴可以自己去试一下。 - 上面第二点已经用
redis
解决了身份认证的问题,下面就是鉴权了,我这个项目是用户携带Token
去访问资源,所以我想了一下,目前来说鉴权还用不到redis
,因为每次都会携带一个Token
,可能我往后写单点登录的时候就需要用到redis
吧。 - 在把
redis
引进来的时候,我们想要在过滤器里边使用redis
,发现redis
的连接方法redisService
是null
,就是无法注入,就是因为listener >> filter >> servlet >> spring
,所以在过滤器阶段,IOC
还没有注入,也就无法使用bean
,最后博主用比较原始的方法,直接生成一个bean
工厂,把bean
给初始化了,这方法虽然感觉不太好,但是可行的,如果其他小伙伴有更好的办法可以一起探讨。可以参考:springboot关于拦截器或者过滤器无法注入bean的问题
好了分析完了,接下来就是编码了。
redis依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
<version>1.3.5.RELEASE</version>
</dependency>
二、 修改
1. 修改CustomUserService
@Service
public class CustomUserService implements UserDetailsService {
//自定义UserDetailsService 接口
@Autowired
UserDao userDao;
@Autowired
PermissionDao permissionDao;
@Autowired
private RedisService redisService;
public UserDetails loadUserByUsername(String username) {
JwtUserDto jwtUserDto;
//这里先去redis查看有没有key,如果有则去获取用户信息,连续调用两次感觉不太好,这里就不优化了
if(RedisCheckUser(username) !=null){
jwtUserDto=RedisCheckUser(username);
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
Map JwtMap = getPermissUrlandMethod(jwtUserDto);
for(Object key : JwtMap.keySet()){
Object value = JwtMap.get(key);
GrantedAuthority grantedAuthority = new UrlGrantedAuthority((String) key,(String)value);
grantedAuthorities.add(grantedAuthority);
}
return new JwtUser(jwtUserDto.getUsername(), jwtUserDto.getPassword(), grantedAuthorities);
}else{
//如果redis里边没有缓存用户信息,说明可能是第一次登录,所以要去数据库查信息
JwtUser user;
user = userDao.findByUserName(username);
if(user.getId() != null){