JWT笔记

什么是JWT

  • 全程为“Json Web Token”,其本质就是一个字符串,是将用户信息保存到一个Json字符串中,然后进行编码后得到token字符串,并且这个token带有签名信息,接收后可以校验是否被篡改,所以可以用于在各方之间安全地将信息作为Json对象传输。

构成

  • 头部.载荷.签名

  • 头部(Header)
    JWT头是一个描述JWT元数据的JSON对象,alg属性表示签名使用的算法,默认为HMAC SHA256(写为HS256);typ属性表示令牌的类型,JWT令牌统一写为JWT。最后,使用Base64 URL算法将上述JSON对象转换为字符串保存。

    {
      "alg": "HS256",
      "typ": "JWT"
    }
    
  • 载荷(Payload)

    {
      "sub": "1234567890",
      "name": "John Doe",
      "iat": 1516239022
    }
    
  • 签名(Signature)

    HMACSHA256(
      base64UrlEncode(header) + "." +
      base64UrlEncode(payload),
      your-256-bit-secret
    )
    

1.所需依赖

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

2.配置application.yml

dragon:
  jwt:
    secret: f4e2e52034348f86b67cde581c0f9eb5 #密钥
    expire: 604800

3.编写工具类

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;

@Component
@Slf4j
@Data
//获取配置文件的属性
@ConfigurationProperties(prefix = "dragon.jwt")
public class JwtUtils {

    private String secret;
    private long expire;
//    private String header;

    /**
     * 生成jwt token
     */
    public String generateToken(long userId) {
        Date nowDate = new Date();
        //过期时间
        Date expireDate = new Date(nowDate.getTime() + expire * 1000);

        return Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setSubject(userId+"")
                .setIssuedAt(nowDate)
                .setExpiration(expireDate)
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    public Claims getClaimByToken(String token) {
        try {
            return Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        }catch (Exception e){
            log.debug("validate is token error ", e);
            return null;
        }
    }

    /**
     * token是否过期
     * @return  true:过期
     */
    public boolean isTokenExpired(Date expiration) {
        return expiration.before(new Date());
    }

    /**
     * 校验token
     */
    public boolean validateJwt(HttpServletRequest request){
        String token = request.getHeader("token");
        return token != null;
    }

4.Controller

    /**
     * 登陆测试
     * @param user
     * @return
     */
    @PostMapping("login")
    public R login(@RequestBody User user, HttpServletResponse response,HttpServletRequest request){
        if (user.getUserName()==null||user.getPassword()==null){
            return R.error();
        }
        String newPassword = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getPassword,newPassword);
        wrapper.eq(User::getUserName,user.getUserName());
        User dbUser = userService.getOne(wrapper);
        //生成token字符串
        String token = jwtUtils.generateToken(dbUser.getId());
        //存入redis
        ValueOperations<String,String> ops = redisTemplate.opsForValue();
        ops.set("tokenOld",token);
        //响应请求头
        response.setHeader("token",token);
//        request.getSession().setAttribute("user",dbUser);
        return token!=null?R.success(dbUser):R.error();
    }

5.拦截器

@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println(new Date() + "--preHandle:" + request.getRequestURL());
        ValueOperations<String,String> ops = redisTemplate.opsForValue();  // 表明取的是key,value型的数据
        Object o = ops.get("tokenOld");  // 获取Redis数据库中key为tokenOld对应的value数据
        String token = request.getHeader("token");
        assert o != null;
        return o.equals(token);//利用用户传入的token和缓存中的token比对
    }
}
posted @ 2022-11-08 22:44  DawsonDragon  阅读(22)  评论(0编辑  收藏  举报