redis存储token实现登录模块(SpringBoot)
redis存储token实现登录模块(SpringBoot)
·
1.原理:
用户登录时,数据库验证账号密码是否正确,若正确则生成token,将token放入redis中存储,并将token传给前端。拦截器拦截每个请求,在请求进入接口前验证head中的token是否已经在redis中,若存在则说明用户已经登录,可以进入其他页面;若不存在说明用户未登录成功,需要去登陆页面重新登录。
2.实现
Step1:
导入redis依赖
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>5.3.3.RELEASE</version>
</dependency>
Step2:
在application.yml中进行相关配置(注意缩进)
spring:
redis:
host: 192.168.xxx.xxx
port: 6379
password:
jedis:
pool:
max-active: 8
database: 0
Step3:
UserController(其实具体逻辑应该放到Service里面,但是我懒QAQ)
/**
* 用户登录
* @param request
* @return
*/
@RequestMapping(value = "/login", method = RequestMethod.POST)
public Result login(@Valid @RequestBody LoginRequest request){
Result result = new Result();
try {
//密码加密
request.setPassword(MD5Util.MD5(request.getPassword()));
//查询用户是否存在
User user = userService.queryByPhoneAndPasswordAndType(request);
if(user == null){
return new Result(false, MessageEnum.Login_User_FAIL);
}
//登录成功,将生成的token存入redis中
String token = UUID.randomUUID().toString().replaceAll("-", "") + "";
//System.out.println(user);
ValueOperations valueOperations = redisTemplate.opsForValue();
valueOperations.set(token, "default", 30, TimeUnit.MINUTES);
result.setFlag(true);
result.setMessage(MessageEnum.Login_User_SUCCESS);
result.setData(token);
}catch (Exception e){
logger.error("用户登录发生异常,param:{}, exception:{}", JSON.toJSONString(request),e);
return new Result(false, MessageEnum.Login_User_Exception);
}
logger.info("用户登录成功, user register param:{}", JSON.toJSONString(request));
return result;
}
Step4:
拦截器拦截请求:利用拦截器将所有访问资源的请求进行拦截,校验head中的token是否合法,不合法直接返回登陆界面,合法则可以正常访问资源。
编写拦截器:
@Component
public class LoginInterceptor implements HandlerInterceptor{
@Autowired
private ObjectMapper objectMapper;
// @Autowired
// private StringRedisTemplate redisTemplate;
@Autowired
private RedisTemplate redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 从请求头里面获取token,因为每次都会在请求头里面携带token
System.out.println(request.getRequestURI());
String token = request.getHeader("TOKEN");
if (StringUtils.isNotBlank(token)) {
//根据head中的token,查询redis中是否有数据
ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
String tokenType = opsForValue.get(token);
// 如果能够获取到数据,说明token未过期
if (StringUtils.isNotBlank(tokenType)) {
return true;
}
}
//从请求头中获取不到token说明未登录,阻止该请求访问资源
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=utf-8");
try {
PrintWriter pw = response.getWriter();
pw.println(objectMapper.writeValueAsString(new Result(false, MessageEnum.Login_User_FAIL)));
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
}
配置拦截器:
@Configuration
public class LoginConfig implements WebMvcConfigurer {
@Resource
private LoginInterceptor loginInterceptor;
//不拦截的请求
String[] excludePatterns = {
"/user/login"};
@Override
public void addInterceptors(InterceptorRegistry registry) {
System.out.println("got there");
// 添加拦截器
registry.addInterceptor(loginInterceptor)
// 要拦截的请求(所有请求)
.addPathPatterns("/**")
// 排除的拦截请求
.excludePathPatterns(excludePatterns);
}
}
3.一些需要注意的坑
(1)在使用RedisTemplate 对value进行set、get时,RedisTemplate 和StringRedisTemplate 不能混用,使用时必须统一。具体原因详见:关于RedisTemplate和StringRedisTemplate不能共用的问题剖析
(2)需要对 redisTemplate 进行序列化处理,才能在redis中get到key对应的value。详见:redis 中我存入了数据,为什么获取不到
更多推荐
已为社区贡献2条内容
所有评论(0)