1、什么是token?
token令牌:是服务端生成的一串随机生成字符串(我们的例子用UUID生成),放在请求头作为客户端进行请求的一个标识。 当用户第一次登录,服务器生成一个token并将此token返回给客户端,以后客户端只需带上这个token前来请求数据即可判断是谁在调用接口,无需再要用户名和密码。
最近有一个需求是权限系统对另一个系统进行token验证权限管理。子系统并未引入权限框架。目前实现思路是前端将token传入子系统。通过共享redis去解决权限问题。故此子系统只需要拦截请求并验证token。
1、引入依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.zx.token</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>token_test</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--springBoot依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--mysql和JDBC依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version> <!--重新设置版本,太低匹配不了云数据库-->
<scope>runtime</scope>
</dependency>
<!--阿里巴巴数据库连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.5</version>
</dependency>
<!--Mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<!--实体方法-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
<!--阿里巴巴json格式-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.35</version>
</dependency>
<!--javaweb的依赖 RequestMappering....等-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--Redis的操作工具jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>
<!--Redis的连接工具-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--连接池-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--test测试工具,不是springBoottest的工具-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2、redis配置yml
redis:
# 地址
host: localhost
# 端口,默认为6379
port: 6379
# 数据库索引
database: 0
# 密码
password: root
# 连接超时时间
timeout: 2000s
lettuce:
pool:
# 连接池中的最小空闲连接
min-idle: 0
# 连接池中的最大空闲连接
max-idle: 8
# 连接池的最大数据库连接数
max-active: 8
# #连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
3、注册过滤器
package com.zkyq.obd.config.handler.filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@Autowired
MyFilter myFilter;
@Bean
public FilterRegistrationBean filterRegistrationBean(){
//注册过滤器(初始化过滤器)
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter);
//添加过滤的路径,凡是路径带/user就进入过滤器
filterRegistrationBean.addUrlPatterns("/realtimememonitoring/*");
return filterRegistrationBean;
}
}
4、过滤
```java
package com.zkyq.obd.config.handler.filter;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.FilterConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
* 作者:kt
* 时间:2022/11/11 11:28
* 描述:过滤器
*/
@Component
public class MyFilter implements Filter {
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("-----------------过滤器初始化----------------");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//校验用户登录状态
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
System.out.println("执行过滤器");
//取出token
String token = request.getHeader("token");
//第一次登录没有token,给null会报错,所以我们判断一下token是否为空,为空给一个空串
//三元运算
token = token == null ? "" : token;
//查询Redis中token的剩余时间
Long expire = redisTemplate.getExpire(token);
if (expire > 0) {
//时间大于0 放行
/*
有一个问题,用户一直在网页上操作,但是token一直在倒计时,操作着操作着就变未登录了
不合理,所以,当用户在操作时,每次经过过滤器调用不同接口时,就重置一下token的时间
*/
redisTemplate.expire("token", 1L, TimeUnit.MINUTES);
//放行
filterChain.doFilter(servletRequest, servletResponse);
} else {
System.out.println("未登录!");
return;
}
}
@Override
public void destroy() {
System.out.println("过滤器已经死亡!");
}
}
至此简单引入过滤就完成。如何构建Srpingboot项目再次不做展示。本文重点是为熟悉springboot项目朋友提供实现过滤器编写思路