Springboot整合JWT
目录
一、Springboot整合JWT
强烈建议小伙伴们阅读 JWT 基础概念:https://www.cnblogs.com/code-duck/p/13479792.html
再进行Springboot整合
1.创建Springboot项目
2.配置pom信息
<!--?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 http://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.3.1.RELEASE</version>
<relativepath>
</relativepath></parent>
<groupid>com.duck.code</groupid>
<artifactid>Springboot-JWT</artifactid>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-web</artifactid>
</dependency>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-test</artifactid>
<scope>test</scope>
</dependency>
<!--引入jwt-->
<dependency>
<groupid>com.auth0</groupid>
<artifactid>java-jwt</artifactid>
<version>3.4.0</version>
</dependency>
<dependency>
<groupid>org.projectlombok</groupid>
<artifactid>lombok</artifactid>
<optional>true</optional>
</dependency>
<!--mybatis plus-->
<dependency>
<groupid>com.baomidou</groupid>
<artifactid>mybatis-plus-boot-starter</artifactid>
<version>3.3.2</version>
</dependency>
<!--代码生成器-->
<dependency>
<groupid>com.baomidou</groupid>
<artifactid>mybatis-plus-generator</artifactid>
<version>3.3.2</version>
</dependency>
<!--逆向工程需要模板引擎-->
<dependency>
<groupid>org.freemarker</groupid>
<artifactid>freemarker</artifactid>
<version>2.3.30</version>
</dependency>
<!--mysql依赖-->
<dependency>
<groupid>mysql</groupid>
<artifactid>mysql-connector-java</artifactid>
<scope>runtime</scope>
</dependency>
<!--连接池-->
<dependency>
<groupid>com.alibaba</groupid>
<artifactid>druid</artifactid>
<version>1.1.20</version>
</dependency>
</dependencies>
</project>
3.配置application配置文件信息
server:
port: 8081
spring:
datasource:
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db_jwt?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
type: com.alibaba.druid.pool.DruidDataSource
mybatis-plus:
global-config:
db-config:
table-prefix: tb_ # 表明前缀
type-aliases-package: com.code.duck.entity # 实体类所在包
mapper-locations: classpath*:/mapper/**Mapper.xml # xml文件所在位置
5.Springboot主启动类配置
@SpringBootApplication
@MapperScan("com.duck.code.mapper")
public class JWTApplication {
public static void main(String[] args) {
SpringApplication.run(JWTApplication.class,args);
}
}
4.Springboot整合MybatisPlus
使用MybatisPlus代码生成器,生成entity、controller、service,service.impl、mapper、xml文件
代码生成器参考本人:Springboot整合MybatisPlus的文章 https://www.cnblogs.com/code-duck/p/13481550.html
6.封装JWT工具类
JWTUtil工具类主要用于生成JWT令牌(token)、核实token信息、对token进行解密
JWT抽象类
JWT抽象类中的三个方法,对应于上述三个功能
public abstract class JWT {
/**
* Decode a given Json Web Token.
*
* @param token with jwt format as string.
* @return a decoded JWT.
*/
public static DecodedJWT decode(String token) throws JWTDecodeException {
return new JWTDecoder(token);
}
/**
* Returns a {@link JWTVerifier} builder with the algorithm to be used to validate token signature.
*
* @param algorithm that will be used to verify the token's signature.
* @return {@link JWTVerifier} builder
* @throws IllegalArgumentException if the provided algorithm is null.
*/
public static Verification require(Algorithm algorithm) {
return JWTVerifier.init(algorithm);
}
/**
* Returns a Json Web Token builder used to create and sign tokens
*
* @return a token builder.
*/
public static JWTCreator.Builder create() {
return JWTCreator.init();
}
}
JWTUtil工具类
public class JWTUtil {
// 用于JWT进行签名加密的秘钥
private static String SECRET = "code-duck-*%#@*!&";
/**
* @Param: 传入需要设置的payload信息
* @return: 返回token
*/
public static String generateToken(Map<string, string=""> map) {
JWTCreator.Builder builder = JWT.create();
// 将map内的信息传入JWT的payload中
map.forEach((k, v) -> {
builder.withClaim(k, v);
});
// 设置JWT令牌的过期时间为60
Calendar instance = Calendar.getInstance();
instance.add(Calendar.SECOND, 60);
builder.withExpiresAt(instance.getTime());
// 设置签名并返回token
return builder.sign(Algorithm.HMAC256(SECRET)).toString();
}
/**
* @Param: 传入token
* @return:
*/
public static void verify(String token) {
JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token);
}
/**
* @Param: 传入token
* @return: 解密的token信息
*/
public static DecodedJWT getTokenInfo(String token) {
return JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token);
}
}
7.UserController控制器中声明登录接口
@RestController
@Slf4j
public class UserController {
@Resource
private UserService userService;
@PostMapping(value = "/user/login")
public Map<string, string=""> userLogin(@RequestBody User user) {
log.info(user.getUsername());
log.info(user.getPassword());
QueryWrapper<user> wrapper = new QueryWrapper<>();
wrapper.eq("username", user.getUsername());
wrapper.eq("password",user.getPassword());
// 数据库中查询用户信息
User one = userService.getOne(wrapper);
HashMap<string, string=""> result = new HashMap<>(); // 返回结果信息给前端
if (one == null){
result.put("code","401");
result.put("msg","用户名或密码错误");
}
Map<string, string=""> map = new HashMap<>(); //用来存放payload信息
map.put("id",one.getId().toString());
map.put("username",one.getUsername());
map.put("role",one.getRole());
// 生成token令牌
String token = JWTUtil.generateToken(map);
// 返回前端token
result.put("code","200");
result.put("msg","登录成功");
result.put("token",token);
return result;
}
}
8.启动Springboot
使用postman进行接口测试,查看是否返回了正确响应,并生成了token令牌
二、为Springboot配置拦截器
- 当用户登录成功时,服务端为该用户生成了一个时长为60的token令牌,
"token": "xxx.xxx.xx"
的形式 以返回给前端系统 - 当前端在每次请求时,我们选择将token令牌放至放入HTTP Header中的Authorization位
- 服务器对所有的请求进行拦截并校验token(除登录接口外)。如果token 信息不正确或过时,则向前端返回错误代码,校验正确则放行。
创建JWT拦截器
在此处进行token校验,如果校验成功则放行,否则返回异常信息给前端系统
public class JWTInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Map<string, string=""> map = new HashMap<>();
//获取请求头中的token令牌
String token = request.getHeader("token");
try {
JWTUtil.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("code", "403");//设置状态
//将 map 转为json jackson
String json = new ObjectMapper().writeValueAsString(map);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(json);
return false;
}
}
配置WebMvcConfigurer拦截器
在此处配置过滤规则:即添加JWTInterceptor token校验拦截器、拦截非登录接口外的一切/user接口
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new JWTInterceptor())
.excludePathPatterns("/user/login") // 登录接口不用于token验证
.addPathPatterns("/user/**"); // 其他非登录接口都需要进行token验证
}
}
在控制器中添加测试接口
@GetMapping(value = "/user/test")
public Map<string,string> test(HttpServletRequest request){
Map<string, string=""> map = new HashMap<>();
//处理自己业务逻辑
String token = request.getHeader("token");
DecodedJWT claims = JWTUtil.getTokenInfo(token);
log.info("用户id: [{}]",claims.getClaim("id").asString());
log.info("用户name: [{}]",claims.getClaim("username").asString());
log.info("用户role: [{}]",claims.getClaim("role").asString());
map.put("code","200");
map.put("msg","请求成功!");
return map;
}
启动Springboot进行测试
- 访问http://localhost:8081/user/login进行登录测试,获取服务器端返回的token信息
- 测试http://localhost:8081/user/test,在其请求头配置token信息
</string,></string,string></string,></string,></string,></string,></string,>