JWT官网地址:https://jwt.io/
1. SpringBoot-JWT Demo结构
2. 数据库准备
只需要一张user表,用于保存用户的用户名和密码。
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, '张三', '123123');
SET FOREIGN_KEY_CHECKS = 1;
3. 代码实现
3.1 导入依赖
<!--JWT-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
3.2 写生成token的方法
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.smallpineapple.springbootjwt.entity.User;
import java.util.Date;
/**
* @author Zeng
* @date 2020/2/17 10:56
*/
public class TokenUtil {
//设置过期时间为1个小时
private static final Long EXPIRE_TIME = Long.valueOf(1*60*60*1000);
public static String getToken(User user){
String token="";
Date date = new Date();
date.setTime(System.currentTimeMillis() + EXPIRE_TIME);
token= JWT.create().withAudience(String.valueOf(user.getId())) //存入需要保存在token里的信息,这里把用户的id存入token中
.withExpiresAt(date)//设置token的过期时间为1小时
.sign(Algorithm.HMAC256(user.getPassword()));//使用HMAC256生成token,密钥是用户的密码
return token;
}
}
3.3 写拦截器对指定路径进行token验证
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.smallpineapple.springbootjwt.entity.User;
import com.smallpineapple.springbootjwt.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Zeng
* @date 2020/2/17 11:00
*/
public class TokenInterceptor implements HandlerInterceptor {
@Autowired
UserService userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//从请求头中获取token
String token = request.getHeader("token");
//执行认证
if(token == null){
throw new RuntimeException("尚未登陆!");
}
//获取token中的userId
String userId;
try {
//从解密的token中获取userId
userId = JWT.decode(token).getAudience().get(0);
} catch (JWTDecodeException j) {
throw new RuntimeException("token异常!请重新登陆");
}
User user = userService.findUserById(Long.valueOf(userId));
if (user == null) {
throw new RuntimeException("未找到该用户!");
}
// 验证上传的token私钥部分是否与用户的密码一致
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
try {
jwtVerifier.verify(token);
} catch (JWTVerificationException e) {
throw new RuntimeException("token异常!请重新登陆");
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
3.4 配置拦截规则
import com.smallpineapple.springbootjwt.interceptor.TokenInterceptor;
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;
/**
* @author Zeng
* @date 2020/2/17 11:18
*/
@Configuration
public class WebMvcConfiguer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getTokenInterceptor())
.addPathPatterns("/admin/**"); //访问以/admin/为前缀的所有路径都需要对token进行验证
}
@Bean
public TokenInterceptor getTokenInterceptor(){
return new TokenInterceptor();
}
}
3.5 写接口并使用Postman测试
import com.smallpineapple.springbootjwt.entity.User;
import com.smallpineapple.springbootjwt.service.UserService;
import com.smallpineapple.springbootjwt.util.ResultUtil;
import com.smallpineapple.springbootjwt.util.TokenUtil;
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;
/**
* @author Zeng
* @date 2020/2/16 22:24
*/
@RestController
public class UserController {
@Autowired
UserService userService;
@PostMapping("/login")
public ResultUtil login(String username, String password){
User dbUser = userService.findUserByUsernameAndPassword(username, password);
if (dbUser == null) {
return ResultUtil.failure().addObject("err", "用户名或密码错误!");
}
//获取token
String token = TokenUtil.getToken(dbUser);
//返回给客户端保存
return ResultUtil.success().addObject("token", token).addObject("user",dbUser);
}
@GetMapping("/admin/test")
public ResultUtil testMethod(){
return ResultUtil.success();
}
}
未登录时尝试访问test接口被拒绝访问
用户登陆获取token
登陆后携带token访问test接口
token失效后尝试携带访问test接口被拒绝
完整项目GitHub地址:https://github.com/SmallPineApp1e/springboot-jwt
时间有限,能力有限,如果有任何错误务必指出!