Token是一种用于验证和授权的令牌,通常用于在客户端和服务器之间进行身份验证和授权。在Web应用程序中,用户在登录后会收到一个token,这个token可以用于后续的请求中,以证明用户的身份和权限。常见的token包括JWT(JSON Web Token)和OAuth Token。Token的使用可以提高安全性,避免在每次请求时都需要重新输入用户名和密码。
在pom文件内添加依赖 添加lombok依赖,简化代码
<!--在此处加入jwt来实现token验证-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
添加两个自定义的注解 config-TokenConfig
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//添加两个自定义的注解
public class TokenConfig {
//定义跳过token验证的注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken{
boolean required() default true;
}
//定义需要Token验证的注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken{
boolean required() default true;
}
}
在idea - file - settings - plugins 搜索lombok下载
创建工具函数来生成token密文(封装函数) utils-TokenTools
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.example.test.pojo.UserInfoPojo;
import java.util.Date;
public class TokenTools {
//生成token密文的函数 UserInfoPojo user需要自己改
public static String getToken(UserInfoPojo user) {
Date start = new Date();//开始生效时间
System.currentTimeMillis()方法来获取当前时间的毫秒数
long currentTime = System.currentTimeMillis() + 60*10 * 1000;//10分钟有效时间
long currentTime = System.currentTimeMillis() + 60*60*1000;//一小时有效时间(根据项目要求)
Date end = new Date(currentTime); //失效时间
//在这里使用了用户的id和密码以生成一个token
String token = JWT.create().withAudience(user.getId().toString()).withIssuedAt(start).withExpiresAt(end)
.sign(Algorithm.HMAC256(user.getPassword()));
return token;
}
}
创建拦截器函数(在访问功能函数前,会检查是否有token注解,有则验证,无则跳过验证) config-AuthenticationInterceptor
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.example.test.pojo.UserInfoPojo;
import com.example.test.service.frontservice.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
//身份验证拦截器
public class AuthenticationInterceptor implements HandlerInterceptor {
@Autowired
private UserService userService;
@Override
//prehandle函数会在Controller里的函数被调用之前提前调用
//所以在这里可以达到提前拦截的效果
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 从 http 请求头中取出 token
String token = request.getHeader("token");
// 如果不是映射到方法直接通过
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();//获取到被注解的函数
//检查函数是否有@PassToken注解,有则直接跳过认证
if (method.isAnnotationPresent(TokenConfig.PassToken.class)) {
TokenConfig.PassToken passToken = method.getAnnotation(TokenConfig.PassToken.class);
if (passToken.required()) {
return true;
}
}
//检查函数是否有UserLoginToken注解, 有则执行验证, 无则执行return true
if (method.isAnnotationPresent(TokenConfig.UserLoginToken.class)) {
TokenConfig.UserLoginToken userLoginToken = method.getAnnotation(TokenConfig.UserLoginToken.class);
if (userLoginToken.required()) {
// 执行认证
if (token == null) {
throw new RuntimeException("当前无token信息,请重新登录!");
}
// 获取 token 中的 userId
String userId;
try {
userId = JWT.decode(token).getAudience().get(0);
} catch (JWTDecodeException j) {
throw new RuntimeException("Token获取失败或有误!");
}
//通过token中的userId来验证是否存在 验证用户名是否重复 userId
//需要自己改 userService.findUserById(userId)
UserInfoPojo up = userService.findUserById(userId);
if (up == null) {
throw new RuntimeException("当前用户ID不存在,请重新登录!");
}
// 通过token中的password与最新查询到password对比 来验证token的正确性
//up.getPassword()需要自己改
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256( up.getPassword() )).build();
try {
jwtVerifier.verify(token); // 密码 / 时间
} catch (JWTVerificationException e) {
throw new RuntimeException("Token获取失败或已过期!");
}
return true;
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object o, Exception e) throws Exception {
}
}
添加拦截器函数的配置文件(设定拦截的访问路径范围) interceptor-InterceptorConfig
interceptor与controller同级
import com.example.test.config.AuthenticationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
//添加拦截器函数的配置文件(设定拦截的访问路径范围)
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor())
.addPathPatterns("/**");
//这里的 /** 代表的是拦截所有的访问路径
}
@Bean
public AuthenticationInterceptor authenticationInterceptor() {
return new AuthenticationInterceptor();
}
}
创建两个pojo实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class JsonMsgPojo {
private boolean status;
private String msg;
private Object data;
}
UserPojo人员信息实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserPojo {
private Long id;
private String un;
private String pw;
private String token;
}
创建登录函数
@PostMapping("login")
public JsonMsgPojo login(UserPojo up){
UserPojo userPojo = userService.login(up);
if (userPojo==null){
return new JsonMsgPojo(false,"用户名或密码错误!",null);
}
return new JsonMsgPojo(true,"登陆成功!",userPojo);
}
创建根据id查询用户的函数
@GetMapping("findUserById")
public JsonMsgPojo findUserById(UserPojo up){
UserPojo userPojo = userService.findUserById(up);
if (userPojo == null){
return new JsonMsgPojo(false,"用户不存在!",null);
}
return new JsonMsgPojo(true,"查询成功!",null);
}
测试token功能
@PostMapping("login")
public JsonMsgPojo login(UserPojo up){
UserPojo userPojo = userService.login(up);
if (userPojo==null){
return new JsonMsgPojo(false,"用户名或密码错误!",null);
}
String token = TokenTools.getToken(userPojo);
userPojo.setToken(token);
return new JsonMsgPojo(true,"登陆成功!",userPojo);
}
携带token访问需要token验证的函数
@TokenConfig.UserLoginToken
@ResponseBody
@GetMapping("userCheck")
public JSONMsgPojo userCheck(long id){
return userService.userCheck(id);
}
token时间失效后需要重新登录,否则访问失败