jwt 用我客户端角度看就是生成token 那就来生成登入token吧 跟上一篇的demo
看这个文章抄的https://www.jianshu.com/p/e88d3f8151db
先看一眼我自己加了jwt后的包结构 加了jwt生成token,拦截器,标识不拦截注释,加了测试Controller
第一步 pom加上依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
第二步 jwt生成token 用@Service注入 TokenService.java
@Service("TokenService")
public class TokenService {
public String getToken(User user) {
String token = "";
try {
// 过期时间,20秒
long EXPIRE_TIME = 20*1000;
// 生成过期时间
Date date = new Date(System.currentTimeMillis()+EXPIRE_TIME);
//用的表在前面文章有放出来 就id name age 就用name假装password了反正能做秘钥就行 withExpiresAt是设置过期时间 去掉就不会过期了 token不变 加上每次调用 token都不一样
token = JWT.create()
.withAudience(user.getId().toString())// 将 user id 保存到 token 里面
.withExpiresAt(date)
.sign(Algorithm.HMAC256(user.getName()));// 以 password 作为 token 的密钥
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return token;
}
}
第三步 写一个跳过验证的接口注释 PassToken
/**
* 用来跳过验证的PassToken
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {
boolean required() default true;
}
第四步 写一个拦截器 AuthenticationInterceptor.java
@Component
public class AuthenticationInterceptor implements HandlerInterceptor {
@Autowired
UserService userService;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token
// 如果不是映射到方法直接通过
if (!(object instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) object;
Method method = handlerMethod.getMethod();
//检查是否有passtoken注释,有则跳过认证
if (method.isAnnotationPresent(PassToken.class)) {
PassToken passToken = method.getAnnotation(PassToken.class);
if (passToken.required()) {
return true;
}
} else {
// 执行认证
if (token == null) {
throw new RuntimeException("无token,请重新登录");
}
// 获取 token 中的 user id
String userId;
try {
userId = JWT.decode(token).getAudience().get(0);
} catch (JWTDecodeException j) {
throw new RuntimeException("401");
}
User user = userService.Sel(userId);
if (user == null) {
throw new RuntimeException("用户不存在,请重新登录");
}
// 验证 token
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getName())).build();
try {
jwtVerifier.verify(token);
} catch (JWTVerificationException e) {
throw new RuntimeException("401");
}
return true;
}
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
第五步 让springboot加载上这个拦截器 InterceptorConfig.java
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
AuthenticationInterceptor interceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor)
.addPathPatterns("/**"); // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
}
}
第六步 原先有的UserController 搞个测试api
@RestController
public class UserController {
@Autowired
private UserService userService;
...
@Autowired
TokenService tokenService;
//登录
@PassToken
@PostMapping("/login")
public Object login(@RequestParam(value = "id", defaultValue = "1") String id, @RequestParam(value = "name", defaultValue = "") String name) {
JSONObject jsonObject = new JSONObject();
//根据id 查用户 原先文章的东西
User userForBase = userService.Sel(id);
if (userForBase == null) {
jsonObject.put("message", "登录失败,用户不存在");
return jsonObject;
} else {
if (!userForBase.getName().equals(name)) {
jsonObject.put("message", "登录失败,密码错误");
return jsonObject;
} else {
String token = tokenService.getToken(userForBase);
jsonObject.put("token", token);
jsonObject.put("user", userForBase);
return jsonObject;
}
}
}
@GetMapping("/getMessage")
public String getMessage() {
return "你已通过验证";
}
}
@PassToken 让登入防止被拦截
第六步 用postman测试 。。因为token放在header上了
没携带token的时候
去获得token的时候
带了token的时候