使用JWT实现Token认证

为何使用JWT?

随着技术的发展,分布式web应用的普及,经过session管理用户登陆状态成本愈来愈高,所以慢慢发展成为token的方式作登陆身份校验,而后经过token去取redis中的缓存的用户信息,随着以后jwt的出现,校验方式更加简单便捷化,无需经过redis缓存,而是直接根据token取出保存的用户信息,以及对token可用性校验,单点登陆更为简单。 这里还有一个在线的的JWT生成器
 

 

 何时你应该用JSON Web Tokens

下列场景中使用JSON Web Token是颇有用的:java

  • Authorization (受权) : 这是使用JWT的最多见场景。一旦用户登陆,后续每一个请求都将包含JWT,容许用户访问该令牌容许的路由、服务和资源。单点登陆是如今普遍使用的JWT的一个特性,由于它的开销很小,而且能够轻松地跨域使用。
  • Information Exchange (信息交换) : 对于安全的在各方之间传输信息而言,JSON Web Tokens无疑是一种很好的方式。由于JWTs能够被签名,例如,用公钥/私钥对,你能够肯定发送人就是它们所说的那我的。另外,因为签名是使用头和有效负载计算的,您还能够验证内容没有被篡改。
 

JSON Web Token的结构是什么样的

JSON Web Token由三部分组成,它们之间用圆点(.)链接。这三部分分别是:web

  • Header
  • Payload
  • Signature

所以,一个典型的JWT看起来是这个样子的:redis

xxxxx.yyyyy.zzzzz算法

接下来,具体看一下每一部分:json

Header

header典型的由两部分组成:token的类型(“JWT”)和算法名称(好比:HMAC SHA256或者RSA等等)。跨域

例如:缓存

而后,用Base64对这个JSON编码就获得JWT的第一部分安全

 

Payload

JWT的第二部分是payload,它包含声明(要求)。声明是关于实体(一般是用户)和其余数据的声明。声明有三种类型: registered, public 和 private。服务器

  • Registered claims : 这里有一组预约义的声明,它们不是强制的,可是推荐。好比:iss (issuer), exp (expiration time), sub (subject), aud (audience)等。
  • Public claims : 能够随意定义。
  • Private claims : 用于在赞成使用它们的各方之间共享信息,而且不是注册的或公开的声明。

下面是一个例子:cookie

对payload进行Base64编码就获得JWT的第二部分

注意,不要在JWT的payload或header中放置敏感信息,除非它们是加密的。

 

Signature

为了获得签名部分,你必须有编码过的header、编码过的payload、一个秘钥,签名算法是header中指定的那个,然对它们签名便可。

例如:

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

签名是用于验证消息在传递过程当中有没有被更改,而且,对于使用私钥签名的token,它还能够验证JWT的发送方是否为它所称的发送方。

 

看一张官网的图就明白了:

 

JSON Web Tokens是如何工做的

  1. 应用(或者客户端)想受权服务器请求受权。例如,若是用受权码流程的话,就是/oauth/authorize
  2. 当受权被许能够后,受权服务器返回一个access token给应用
  3. 应用使用access token访问受保护的资源(好比:API)

 

 
使用JWT核心代码:
maven依赖:
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
     <version>3.2.0</version>
</dependency>
<dependency>
     <groupId>io.jsonwebtoken</groupId>
     <artifactId>jjwt</artifactId>
     <version>0.7.0</version>
</dependency>

JWT工具类:
用于生成Token,和Token验证

public class JwtUtils {
    /**
     * 签发JWT
     * 
     * @param id
     * @param subject   能够是JSON数据 尽量少
     * @param ttlMillis
     * @return String
     *
     */
    public static String createJWT(String id, String subject, long ttlMillis) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        SecretKey secretKey = generalKey();
        JwtBuilder builder = Jwts.builder().setId(id).setSubject(subject) // 主题
                .setIssuer("user") // 签发者
                .setIssuedAt(now) // 签发时间
                .signWith(signatureAlgorithm, secretKey); // 签名算法以及密匙
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date expDate = new Date(expMillis);
            builder.setExpiration(expDate); // 过时时间
        }
        return builder.compact();
    }

    /**
     * 验证JWT
     * 
     * @param jwtStr
     * @return
     */
    public static CheckResult validateJWT(String jwtStr) {
        CheckResult checkResult = new CheckResult();
        Claims claims = null;
        try {
            claims = parseJWT(jwtStr);
            checkResult.setSuccess(true);
            checkResult.setClaims(claims);
        } catch (ExpiredJwtException e) {
            checkResult.setErrCode(SystemConstant.JWT_ERRCODE_EXPIRE);
            checkResult.setSuccess(false);
        } catch (SignatureException e) {
            checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
            checkResult.setSuccess(false);
        } catch (Exception e) {
            checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
            checkResult.setSuccess(false);
        }
        return checkResult;
    }

    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.decode(SystemConstant.JWT_SECERT);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }

    /**
     * 
     * 解析JWT字符串
     * 
     * @param jwt
     * @return
     * @throws Exception
     */
    public static Claims parseJWT(String jwt) throws Exception {
        SecretKey secretKey = generalKey();
        return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();
    }
}

如何使用?
代码实例:

public class LoginController {
    @Autowired
    UserRepository userRepository;
    

    @RequestMapping(value="login",method = RequestMethod.POST)
    public ReturnVo login(String username, String password,HttpServletResponse
            response) {
        User user =  userRepository.findByUsername(username);
        if(user!=null){
            if(user.getPassword().equals(password)){
                //把token返回给客户端-->客户端保存至cookie-->客户端每次请求附带cookie参数
                String JWT = JwtUtils.createJWT("1", username, SystemConstant.JWT_TTL);
                return ReturnVo.ok(JWT);
            }else{
                return ReturnVo.error();
            }
        }else{
            return ReturnVo.error();
        }
    }

@RequestMapping(value="description",method = RequestMethod.POST) public ReturnVo description(String username) { User user = userRepository.findByUsername(username); return ReturnVo.ok(user.getDescription()); } }
相关文章
相关标签/搜索