1.Token
token:服务端生成的一串字符串,可以解决频繁登录的问题
它作为客户端进行请求的一个令牌:
第一次登录后,服务器生成一个token返回给客户端;
客户端只需要带上token来请求数据即可,无需再次带上用户名和密码
2.使用目的
为了减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮
3.Token存放在客户端
服务端生成的Token
存放在客户端的Token
1.JWT的pom包
<!-- JWT技术的依赖包-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
2.JWT工具类
private static final String jwtToken = "xiaosuda"; //C部分;签名
//生成Token:通过UserId创建Token
public static String createToken(Long userId){
Map<String,Object> claims = new HashMap<>();
claims.put("userId",userId);
JwtBuilder jwtBuilder = Jwts.builder()
.signWith(SignatureAlgorithm.HS256, jwtToken) //A部分;表头
.setClaims(claims) //B部分;负载
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000));
String token = jwtBuilder.compact();
return token;
}
//解析Token
public static Map<String, Object> checkToken(String token){
try {
Jwt parse = Jwts.parser().setSigningKey(jwtToken).parse(token);
return (Map<String, Object>) parse.getBody();
}catch (Exception e){
e.printStackTrace();
}
return null;
}
这里解析token可以更简单的写直接返回clams获得各种信息,因为我后面还做了封装
3.登录生成token逻辑
@Override
public Result login(LoginParams loginParams) {
String account = loginParams.getAccount(); //拿到账号
String password = loginParams.getPassword(); //拿到密码
String slat = loginParams.getSlat(); //拿到加密盐
//根据用户名和密码取user表中查询,查询是否存在
if (StringUtils.isBlank(account)||StringUtils.isBlank(password)){
return Result.fail(ErrorCode.PARAMS_ERROR.getCode(),ErrorCode.PARAMS_ERROR.getMsg());
}
password= DigestUtils.md5Hex(password + slat);
SysUser sysUser = sysUserService.findUser(account,password);
//每次登录生成新的token
String token = JWTUtils.createToken(sysUser.getId());
System.out.println("=================================");
System.out.println("第一次登陆的的token: "+token);
System.out.println("=================================");
return Result.success(token);
}
这样登入成功后客户端会存放一个token
/*
登录后用户:验证token是否合法的方法
*/
@Override
public SysUser checkToken(String token) {
//判断是否为空
if (StringUtils.isBlank(token)){
System.out.println("前端没有传来token");
return null;
}
Map<String, Object> stringObjectMap = JWTUtils.checkToken(token);
//解析是否成功
if (stringObjectMap == null){
System.out.println("token解析未成功");
return null;
}
String userJson = redisTemplate.opsForValue().get("TOKEN_" + token);
//Redis是否校验成功
if (StringUtils.isBlank(userJson)){
System.out.println("redis中token不正确");
return null;
}
SysUser sysUser = JSON.parseObject(userJson, SysUser.class);
return sysUser;
}
这里对校验token进行了进一步封装,原本逻辑是直接调用JWT工具类中的checktoken生成claims
@Override
public Result findUserByToken(String token) {
//校验失败:通过 loginService.checkToken 的方法实现以上三个检查条件
SysUser sysUser = loginService.checkToken(token);
if (sysUser == null){
return
Result.fail(ErrorCode.TOKEN_ERROR.getCode(),ErrorCode.TOKEN_ERROR.getMsg());
}
LoginUserVo loginUserVo = new LoginUserVo();
loginUserVo.setId(String.valueOf(sysUser.getId()));
loginUserVo.setNickname(sysUser.getNickname());
loginUserVo.setAvatar(sysUser.getAvatar());
loginUserVo.setAccount(sysUser.getAccount());
return Result.success(loginUserVo); //验证成功
}