使用JWT
用户认证的逻辑
- 设置拦截器,携带token且token合法的请求,允许通过,否则拦截。
- 获取token的接口,将用户名和密码携带,换取token。
实现方案
- 引入依赖
<!--引入jwt 用户token生成,用户登录验证-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
- 添加认证工具类
public class JWTUtil {
private static final String SECRET = "iwqjhda8232bjgh432[cicada-smile]";
public static String getToken(Map<String, String> map) {
Calendar instance = Calendar.getInstance();
instance.add(Calendar.DATE, 7);//默认7天过期
//创建jwt builder
JWTCreator.Builder builder = JWT.create();
//payload
map.forEach(builder::withClaim);
String token = builder.withExpiresAt(instance.getTime())//指定令牌过期时间
.sign(Algorithm.HMAC256(SECRET));//sign
return token;
}
/**
* 验证token 合法性
*/
public static DecodedJWT verify(String token) {
return JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token);
}
}
- 添加拦截器
public class AuthInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
Map<String, Object> map = new HashMap<>();
//获取请求头中令牌
String token = request.getHeader("token");
try {
JWTUtil.verify(token);//验证令牌
return true;//放行请求
} catch (Exception e) {
e.printStackTrace();
}
map.put("msg", "token无效");
map.put("success", false);//设置状态
//将map 专为json jackson
String json = new ObjectMapper().writeValueAsString(map);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(json);//返回给前端结果
return false;
}
}
加入到SpringMvc
中
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/user/login","/user/getUser");
}
}
- 登录接口
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("/login")
public Map<String, Object> login(@RequestBody Map<String, String> user) {
Map<String, Object> result = new HashMap<>();
if ("admin".equals(user.get("userName")) && "123456".equals(user.get("password"))) {
Map<String, String> payload = new HashMap<>();
payload.put("userName", user.get("userName"));
//生成JWT的令牌
String token = JWTUtil.getToken(payload);
result.put("token", token);
}
return result;
}
@GetMapping("/getUser")
public String getUser(@RequestParam String token) {
DecodedJWT verify = JWTUtil.verify(token);
String userName = verify.getClaim("userName").asString();
return userName;
}
@GetMapping("/visit")
public String visit() {
return "这是一段精彩的内容";
}
}
使用Redis
用户认证的逻辑
- 设置拦截器,携带token且token在redis中存在的,允许通过,否则拦截。
- 认证接口,允许匿名访问。登录成功之后,设置token存放到redis中,设置过期时间。
实现方案
- 引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 新增Redis的配置
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
}
- 新增拦截器
public class AuthRedisInterceptor implements HandlerInterceptor {
@Autowired
RedisTemplate<String, Object> redisTemplate;
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
Map<String, Object> map = new HashMap<>();
//获取请求头中令牌
String token = request.getHeader("token");
Map<Object, Object> userMap = redisTemplate.opsForHash().entries(TOKEN_PREFIX + token);
if (!userMap.isEmpty()) {
return true;
}
map.put("msg", "token无效");
map.put("success", false);//设置状态
//将map 专为json jackson
String json = new ObjectMapper().writeValueAsString(map);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(json);//返回给前端结果
return false;
}
}
- 将拦截器加入到Spring中
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Bean
public AuthRedisInterceptor authRedisInterceptor() {
return new AuthRedisInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authRedisInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/user/login", "/user/getUser");
}
}
- 新增前缀常量
public class Constants {
public final static String TOKEN_PREFIX = "AUTH:TOKEN:";
}
- 新增访问接口
@RestController
@RequestMapping("/user")
public class UserRedisController {
@Autowired
RedisTemplate<String, Object> redisTemplate;
@PostMapping("/login")
public String login(@RequestBody Map<String, String> user) {
Map<String, Object> result = new HashMap<>();
String token = UUID.randomUUID().toString();
if ("admin".equals(user.get("userName")) && "123456".equals(user.get("password"))) {
redisTemplate.opsForHash().putAll(TOKEN_PREFIX + token, user);
redisTemplate.expire(TOKEN_PREFIX + token, 30, TimeUnit.HOURS);
}
return token;
}
@GetMapping("/getUser")
public String getUser(@RequestParam String token) {
Map<Object, Object> entries = redisTemplate.opsForHash().entries(TOKEN_PREFIX + token);
return entries.toString();
}
@GetMapping("/visit")
public String visit() {
return "这是一段精彩的内容";
}
}