之前一直使用的是cookie session的方式进行接口访问的判断,后续在换架构之后使用分布式springcloud搭建项目,接触了token的接口权限校验感觉还不错所以记录一下。
首先来看一下目录结构
首先需要用的的环境是jdk8及以上,maven,关系型数据库。
开始创建一个maven项目
下面是需要用到的依赖(依赖下不到的可以百度)
<dependencies> <!--引入jwt依赖--> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.4.1</version> </dependency> <!-- 引入mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.1</version> </dependency> <!--mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.22</version> <optional>true</optional> </dependency> <!-- web依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
接下来是jwt的工具类
package com.utils; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTCreator; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.AlgorithmMismatchException; import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.exceptions.TokenExpiredException; import com.auth0.jwt.interfaces.DecodedJWT; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Calendar; import java.util.HashMap; import java.util.Map; public class JwtUtils { //密钥(设置一个比较复杂的) private static final String SING = "123456"; /** * 生成token */ public static String getToken(Map<String,String> map) { Calendar instance = Calendar.getInstance(); //默认7天过期 // instance.add(Calendar.DATE, 7); //这里设置3min过期 instance.add(Calendar.MINUTE, 3); //创建jwt builder JWTCreator.Builder builder = JWT.create(); map.forEach((k, v) -> { builder.withClaim(k, v); }); String token = builder.withExpiresAt(instance.getTime())//有效期 .sign(Algorithm.HMAC256(SING));//密钥 return token; } /** * 验证token合法性 */ public static DecodedJWT verify(String token){ //返回验证结果(结果是内置的) return JWT.require(Algorithm.HMAC256(SING)).build().verify(token); } }
拦截器,用来拦截是否需要携带token请求头请求接口
package com.config;
import com.interceptor.JwtInterceptor;
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(new JwtInterceptor())
//拦截
.addPathPatterns("/**")
//放行
.excludePathPatterns("/user/login");
}
}
token校验后的错误码返回拦截器
package com.interceptor;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import com.utils.JwtUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class JwtInterceptor implements HandlerInterceptor {
private static final Logger log = LoggerFactory.getLogger(JwtInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
Map<String, Object> map = new HashMap<>();
// 获取请求头中的令牌
String token = request.getHeader("token");
log.info("请求头中的token是:{}",token);
try {
if(token==null){
throw new Exception();
}
//验证令牌
DecodedJWT verify = JwtUtils.verify(token);
return true;
} catch (SignatureVerificationException e){
//e.printStackTrace();
map.put("msg","无效签名");
} catch (TokenExpiredException e){
//e.printStackTrace();
map.put("msg","token过期");
} catch (AlgorithmMismatchException e){
//e.printStackTrace();
map.put("msg","token算法不一致");
} catch (Exception e){
//e.printStackTrace();
map.put("msg","token无效");
}
map.put("state",false);
//将map转为json
String json = new ObjectMapper().writeValueAsString(map);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(json);
return false;
}
}
用户的实体
package com.pojo;
public class User {
private String id;
private String username;
private String password;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
写一个用于测试的controller试试吧!
package com.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import com.pojo.User;
import com.service.UserService;
import com.utils.JwtUtils;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
@RestController
public class UserController {
private static final Logger log = LoggerFactory.getLogger(UserController.class);
@Autowired
private UserService userService;
@GetMapping("/user/login")
public Map<String,Object> login(User user) {
log.info("用户名:[{}]", user.getUsername());
log.info("密码:[{}]", user.getPassword());
Map<String, Object> map = new HashMap<>();
try {
// 这里就不请求数据库了原理一样,模拟请求到的数据
// User userDB = userService.login(user);
User userDB =new User();
userDB.setUsername("admin");
userDB.setId("1001");
Map<String, String> payload = new HashMap<>();
//用户登录成功后的信息放入payload
payload.put("id", userDB.getId());
payload.put("username", userDB.getUsername());
//生成JWT令牌,提示token加密方式是base64所以不要再token中存放敏感信息
String token = JwtUtils.getToken(payload);
map.put("state", true);
map.put("token", token);
map.put("msg", "认证成功");
} catch (Exception e) {
map.put("state", false);
map.put("msg", e.getMessage());
}
return map;
}
@PostMapping("/user/test")
public Map<String,Object> test1(String token){
Map<String, Object> map = new HashMap<>();
map.put("msg","访问成功!!!");
return map;
}
}
结果成功!
下面试试被token拦截的请求在不带token的情况下请求的返回结果
这个是token过期的情况
token验证成功的情况