JWT - 结合redis与cookie进行优化
JWT - 结合redis与cookie进行优化
1.在工程中导入cookie工具类
package com.heima.utils.common;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
public class CookieUtil {
/**
* 设置cookie
*
* @param response
* @param name cookie名字
* @param value cookie值
* @param maxAge cookie生命周期 以秒为单位
*/
public static void addCookie(HttpServletResponse response, String domain, String path, String name,
String value, int maxAge, boolean httpOnly) {
Cookie cookie = new Cookie(name, value);
cookie.setDomain(domain);
cookie.setPath(path);
cookie.setMaxAge(maxAge);
cookie.setHttpOnly(httpOnly);
response.addCookie(cookie);
}
/**
* 根据cookie名称读取cookie
* @param request
* @return map<cookieName,cookieValue>
*/
public static Map<String,String> readCookie(HttpServletRequest request, String ... cookieNames) {
Map<String,String> cookieMap = new HashMap<String,String>();
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
String cookieName = cookie.getName();
String cookieValue = cookie.getValue();
for(int i=0;i<cookieNames.length;i++){
if(cookieNames[i].equals(cookieName)){
cookieMap.put(cookieName,cookieValue);
}
}
}
}
return cookieMap;
}
}
2.admin端改造
2.1 apis工程
public ResponseResult login(AdUserDto dto, HttpServletResponse response);
2.2 admin工程Controller - 登录接口
@RestController
@RequestMapping("/login")
@CrossOrigin
public class LoginController implements LoginControllerApi {
@Autowired
private UserLoginService userLoginService;
@PostMapping("/in")
@Override
public ResponseResult login(@RequestBody AdUserDto dto, HttpServletResponse response) {
CookieUtil.addCookie(response, "localhost", "/", "uid",dto.getName() , -1, false);
return userLoginService.login(dto);
}
}
2.3 ServiceImpl - 登录业务
@Service
public class UserLoginServiceImpl extends ServiceImpl<AdUserMapper, AdUser> implements UserLoginService {
@Autowired
private RedisTemplate redisTemplate;
@Override
public ResponseResult login(AdUserDto dto) {
//1.检查参数
if (StringUtils.isEmpty(dto.getName()) || StringUtils.isEmpty(dto.getPassword())) {
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "用户名或密码错误");
}
//2.查询数据库中的用户信息
List<AdUser> list = list(Wrappers.<AdUser>lambdaQuery().eq(AdUser::getName, dto.getName()));
if(list != null && list.size() ==1){
AdUser adUser = list.get(0);
//3.比对密码
String pswd = DigestUtils.md5DigestAsHex((dto.getPassword()+adUser.getSalt()).getBytes());
if(adUser.getPassword().equals(pswd)){
//4.返回数据jwt
Map<String,Object> map = new HashMap<>();
map.put("token",AppJwtUtil.getToken(adUser.getId().longValue()));
adUser.setPassword("");
adUser.setSalt("");
map.put("user",adUser);
//将jti作为redis的key jwt作为reids的value进行存储
String token = AppJwtUtil.getToken(adUser.getId().longValue());
redisTemplate.boundValueOps(adUser.getName()).set(token);
return ResponseResult.okResult(map);
}else {
return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR);
}
}else {
return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"用户不存在");
}
}
}
3.网关gateway工程改造 - 其它业务进行token校验
@Autowired
private RedisTemplate redisTemplate;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//1.获取请求对象和响应对象
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
//2.判断当前的请求是否为登录,如果是,直接放行
if (request.getURI().getPath().contains("/login/in")) {
//放行
return chain.filter(exchange);
}
//3.获取当前用户的请求头jwt信息
//HttpHeaders headers = request.getHeaders();
//String jwtToken = headers.getFirst("token");
//4.判断当前令牌是否存在
//if (StringUtils.isEmpty(jwtToken)) {
// //如果不存在,向客户端返回错误提示信息
// response.setStatusCode(HttpStatus.UNAUTHORIZED);
// return response.setComplete();
//}
//2.从cookie中获取jti的值,如果该值不存在,拒绝本次访问
String username = this.getJtiFromCookie(request);
if (org.apache.commons.lang.StringUtils.isEmpty(username)) {
//拒绝访问
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
//3.从redis中获取jwt的值,如果该值不存在,拒绝本次访问
String jwtToken = this.getJwtFromRedis(username);
if (org.apache.commons.lang.StringUtils.isEmpty(jwtToken)) {
//拒绝访问
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
try {
//5.如果令牌存在,解析jwt令牌,判断该令牌是否合法,如果不合法,则向客户端返回错误信息
Claims claims = AppJwtUtil.getClaimsBody(jwtToken);
int result = AppJwtUtil.verifyToken(claims);
if (result == 0 || result == -1) {
//5.1 合法,则向header中重新设置userId
Integer id = (Integer) claims.get("id");
log.info("find userid:{} from uri:{}", id, request.getURI());
//重新设置token到header中
ServerHttpRequest serverHttpRequest = request.mutate().headers(httpHeaders -> {
httpHeaders.add("userId", id + "");
}).build();
exchange.mutate().request(serverHttpRequest).build();
}
} catch (Exception e) {
e.printStackTrace();
//想客户端返回错误提示信息
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
//6.放行
return chain.filter(exchange);
}
/* *
* 优先级设置
* 值越小,优先级越高
*
* @return
*/
@Override
public int getOrder() {
return 0;
}
private String getJtiFromCookie(ServerHttpRequest request) {
HttpCookie httpCookie = request.getCookies().getFirst("uid");
if (httpCookie != null){
String username = httpCookie.getValue();
return username;
}
return null;
}
//从redis中获取jwt
private String getJwtFromRedis(String username) {
String jwt = (String) redisTemplate.boundValueOps(username).get();
return jwt;
}
注意: 别忘记导入redis及web相关依赖