JWT简介【第一位大哥解释了token是什么怎么用 第二个大哥详细解释了三部分的组成】
(18条消息) 初见Token、JWT结构和Java的JJWT实现JWT(简洁明了的了解Token,以及Token认证和Cookie认证的区别)_天道酬勤-CSDN博客_jjwt和java-jwt
基于jwt的token验证 - 奕锋博客 - 博客园 (cnblogs.com)
实现步骤
- maven引入依赖
- 生成token的工具类
- controller层接收前端的请求
- service层查询用户信息并生成token返回给前端
- 前端将信息保存在 cookie中
环境准备
- JWT依赖【这里使用的依赖是jjwt 支持更高级的应用 此外还有别的token插件 Auth0将依赖代码也放到这里了】
<!-- jwt 依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!--另一种token插件 性能更高-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.10.3</version>
</dependency>
- token工具类【生成token 校验token 根据token获取私有部分的用户信息】
import io.jsonwebtoken.*;
import org.springframework.util.StringUtils;
import java.util.Date;
public class JwtHelper {
// token 失效时间 当前设置过期时间 24小时
private static long tokenExpiration = 24*60*60*1000;
//生成token 的私有盐 这个按道理来说只有自己知道 加密的时候加入盐 token就不会轻易的被破解
private static String tokenSignKey = "123456";
/**
* 生成jwt令牌【token】 也可以根据别的用户信息生成token 这里选择了 userId userName
* @param userId 用户id
* @param userName 用户名
* @return
*/
public static String createToken(Long userId,String userName){
String token = Jwts.builder()
//公共部分
.setSubject("YYGH-USER")
//设置token 的过期时间
.setExpiration(new Date(System.currentTimeMillis()+tokenExpiration))
//私有部分
.claim("userId",userId)
.claim("userName",userName)
//签名部分 设置加密算法 + 自己的盐
.signWith(SignatureAlgorithm.HS512,tokenSignKey)
//对token的压缩方法 载荷过长可以进行压缩
.compressWith(CompressionCodecs.GZIP)
.compact();
return token;
}
/**
* 根据token 得到用户ID
* @param token
* @return
*/
public static Long getUserIdByToken(String token){
//判断token是否 null
if(StringUtils.isEmpty(token)) return null;
/**
* 根据自定义的盐值解析token 获取token里面私有部分的信息
*
* tokenSignKey 自己设置的盐
* token 传过来的token
*/
Jws<Claims> claimsJwts = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
//私有部分的数据体
Claims jwtsBody = claimsJwts.getBody();
Long userId = (Long) jwtsBody.get("userId");
return userId;
}
/**
* 根据token 获取用户名称
* @param token
* @return
*/
public static String getUserNameByToken(String token){
if(StringUtils.isEmpty(token)) return "";
Jws<Claims> claimsJws
= Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
return (String)claims.get("userName");
}
3.controller层代码
@Api(value = "用户相关接口")
@RestController
@RequestMapping("/api/user")
public class UserInfoApiController {
@Autowired
private UserInfoService userInfoService;
@ApiOperation(value = "用户登录")
@PostMapping("login")
public R login(@RequestBody LoginVo loginVo, HttpServletRequest request){
//获取用户登录的ip地址【这里是我自己封装的获取用户ip的工具类 你可以使用HuTool工具包等自己实现】
loginVo.setIp(IpUtils.getIpAddr(request));
//执行登录请求 当前登录的业务自己实现 不一定要跟我一样
Map<String, Object> info = userInfoService.login(loginVo);
//判断是否登录成功
String message = (String) info.get("msg");
if(!StringUtils.isEmpty(message)){
return R.error().data("message",message);
}
//返回登录信息和token
return R.ok().data(info);
}
}
4.service层代码【我这里面的逻辑判断 有些麻烦 大家根据自己情况 实现不同的校验】
@Autowired
private RedisTemplate<String,String> redisTemplate;
@Override
public Map<String, Object> login(LoginVo loginVo) {
Map<String, Object> map = new HashMap<>();
/**
* 获取手机号和验证码
* 1:校验是否为空
* 2:校验验证码是否正确
* 3:校验手机号是否存在 不存在自动注册
* 4:如果已存在 校验手机号手机否被删除或禁用
*/
String phone = loginVo.getPhone();
String code = loginVo.getCode();
if(StringUtils.isEmpty(phone)){
map.put("msg","手机号码不能为空");
return map;
}
if(StringUtils.isEmpty(code)){
map.put("msg","验证码不能为空");
return map;
}
//TODO 校验验证码 从缓存区获取验证码 跟前端传过来的验证码做对比
//当前我这里是SpringcLoud项目 整合了redis 不需要的同志可以直接删除【按照自己的逻辑来】
String phoneCode = redisTemplate.opsForValue().get(phone);
if(!code.equals(phoneCode)){
map.put("msg","手机验证码错误");
return map;
}
//手机号不存在 自动注册
QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
wrapper.eq("phone",phone);
UserInfo userInfo = baseMapper.selectOne(wrapper);
if(userInfo == null){
userInfo = new UserInfo();
userInfo.setName("");
userInfo.setPhone(phone);
userInfo.setStatus(1);
baseMapper.insert(userInfo);
}
//如果账号存在 但是已经被禁用
if(userInfo.getStatus() == 0){
map.put("msg","账号已被禁用,请联系客服");
return map;
}
//上面所有的校验都通过以后 Controller层返回用户信息
String name = userInfo.getName();
if(!StringUtils.isEmpty(name)){
name = userInfo.getNickName();
}
if(StringUtils.isEmpty(name)) {
name = userInfo.getPhone();
}
map.put("name",name);
//jwt 生成 token 字符串
String token = JwtHelper.createToken(userInfo.getId(),name);
map.put("token",token);
return map;
}
如何校验token和别的token工具的使用 这位大哥已经详细给我们说了
(18条消息) Token插件:Auth0和jjwt对比_进击的小白-CSDN博客
- 前端保存cookie信息 我这里使用的是 js-cookie 【前端是vue框架】