用户ID和token:
已经登陆的用户:
{
"status": 200,
"msg": "登录成功!",
"data": {
"userId": "83c68099-6522-4d22-a841-7059089c18cd",
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6Ijgz
YzY4MDk5LTY1MjItNGQyMi1hODQxLTcwNTkwODljMThjZCIsInR5cGUiOiLn
lKjmiLciLCJleHAiOjE2NDY4MjA1MjgsImFjY291bnQiOiJhZW93dWd1b3poaS14eCJ9.QUuwS_24gJz7XxgHVUCDPGkGnp6j3e4p-lOHXpA_UeU"
}
}
未进行登陆的用户:
userId:b3893569-94f2-420a-a3d3-827b6c8cafe6
使用未登录的用户ID登陆系统: 登陆一个正常使用的用户:
{
"status": 200,
"msg": "登录成功!",
"data": {
"userId": "83c68099-6522-4d22-a841-7059089c18cd",
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6Ijgz
YzY4MDk5LTY1MjItNGQyMi1hODQxLTcwNTkwODljMThjZCIsInR5cGUiOiLn
lKjmiLciLCJleHAiOjE2NDY4MjA1MjgsImFjY291bnQiOiJhZW93dWd1b3poaS14eC
J9.QUuwS_24gJz7XxgHVUCDPGkGnp6j3e4p-lOHXpA_UeU"
}
}
然后拿这个正常登录的用户的token去给未登录的用户进行token验证; 结果是拿到了未登录用户的个人信息。如下图A所示
思考:为进行登录的用户可以拿着已经登录的用户的token进行访问自己的信息,这样河里吗?不河里!所以怎么办呢? 解决办法: 使用token里面PayLoad里的userId的信息,再次跟请求参数的userId验证一致性。 具体代码如下: 用户登录ServiceImpl:
@Override
@Transactional(propagation = Propagation.SUPPORTS)
public Map<String,String> login(String account,String password) {
try{
QueryWrapper<User> wrapper = new QueryWrapper();
wrapper.eq("account",account).eq("password",MD5Utils.md5(password));
User userDB = userdao.selectOne(wrapper);
if(userDB != null){
Map<String,String> Payload = new HashMap<>();
Payload.put("id",userDB.getId());
Payload.put("account",userDB.getAccount());
Payload.put("type", UserTypeEnum.USER.getName());
String token = JwtUtil.createJwtToken(Payload, 120);
redisTemplate.opsForValue().set(User.class.getSimpleName() + "_"+ userDB.getId(), GsonUtil.getGson().toJson(userDB));
Map<String,String>map = new HashMap<>();
map.put("token",token);
map.put("userId",userDB.getId());
return map;
}
throw new MsgException("登陆失败,用户名或密码错误");
}catch (MsgException e){
throw e;
}catch(RedisConnectionFailureException e){
log.warn(e.getMessage(),e);
throw new MsgException("Redis缓存连接失败!");
} catch (Exception e){
throw e;
}
}
LoginInterceptor登录拦截器,做token检查的
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
try{
String token = request.getHeader("token");
if(token == null || token.equals("")){
throw new MsgException("未携带token");
}
JwtUtil.verifyToken(token);
return true;
}catch (MsgException e){
throw e;
}catch (JWTDecodeException e){
throw new MsgException("token过期,请重新登录");
}catch (TokenExpiredException e){
throw new MsgException("token过期,请重新登录");
}
catch (Exception e){
throw e;
}
}
JudgeUserIdUtil: 从HttpServletRequest里面的Header取出token,在从token的Payload取出userId,对比传入的userId。
public class JudgeUserIdUtil {
public static Boolean Judge(HttpServletRequest request,String userId){
String token = request.getHeader("token");
DecodedJWT decodedJWT = JwtUtil.verifyToken(token);
String userIdInToken = decodedJWT.getClaim("id").asString();
if(userId.equals(userIdInToken)){
return true;
}
return false;
}
}
代码修改完毕后,当未登录的用户使用别人登录后的token进行访问系统,图A再次发送请求,系统会提示非法请求。 总结: 1,登录的时候将用户ID放进去Payload里 2,然后如果一些request请求有userId参数,那就使用token里Payload里取出userId2, 3,userId参数和userId2进行对比,如果一致那就OK,如果不一致那就不允许访问。
PS:或许我们可以使用sa-token来解决这样的问题?博主未学习sa-token,不敢断言。 以上博文若有言辞不当,望诸君不吝赐教。
|