目录java
JWT(JSON Web Token)是一个开放标准(RFC 7519),它定义了一种紧凑且独立的方式,能够在各个系统之间用JSON做为对象安全地传输信息,而且能够保证所传输的信息不会被篡改。git
JWT一般有两种应用场景:github
本文讨论第一点,如何利用JWT来实现对API的受权访问。这样就只有通过受权的用户才能够调用API。web
JWT由三部分组成,用.
分割开。算法
第一部分为Header
,一般由两部分组成:令牌的类型,即JWT,以及所使用的加密算法。json
{ "alg": "HS256", "typ": "JWT" }
Base64
加密后,就变成了:api
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
第二部分为Payload
,里面能够放置自定义的信息,以及过时时间、发行人等。安全
{ "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }
Base64
加密后,就变成了:服务器
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
第三部分为Signature
,计算此签名须要四部分信息:app
Header
里的算法信息Header
Payload
接受到JWT后,利用相同的信息再计算一次签名,然年与JWT中的签名对比,若是不相同则说明JWT中的内容被篡改。
将上面三部分都编码后再合在一块儿就获得了JWT。
须要注意的是,JWT的内容并非加密的,只是简单的Base64
编码。也就是说,JWT一旦泄露,里面的信息能够被轻松获取,所以不该该用JWT保存任何敏感信息。
HTTP
的Authorization
头里)<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> </dependency>
这里使用了一个叫JJWT(Java JWT)的库。
public String generateToken(String payload) { return Jwts.builder() .setSubject(payload) .setExpiration(new Date(System.currentTimeMillis() + 10000)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact(); }
public String parseToken(String jwt) { return Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(jwt) .getBody() .getSubject(); }
public boolean isTokenValid(String jwt) { try { parseToken(jwt); } catch (Throwable e) { return false; } return true; }
JJWT
并无提供判断JWT是否合法的方法,可是在解码非法JWT时会抛出异常,所以能够经过捕获异常的方式来判断是否合法。@GetMapping("/registration") public String register(@RequestParam String username, HttpServletResponse response) { String jwt = jwtService.generateToken(username); response.setHeader(JWT_HEADER_NAME, jwt); return String.format("JWT for %s :\n%s", username, jwt); }
Authorization
头里。@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) request; HttpServletResponse httpServletResponse = (HttpServletResponse) response; String jwt = httpServletRequest.getHeader(JWT_HEADER_NAME); if (WHITE_LIST.contains(httpServletRequest.getRequestURI())) { chain.doFilter(request, response); } else if (isTokenValid(jwt)) { updateToken(httpServletResponse, jwt); chain.doFilter(request, response); } else { httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED); } } private void updateToken(HttpServletResponse httpServletResponse, String jwt) { String payload = jwtService.parseToken(jwt); String newToken = jwtService.generateToken(payload); httpServletResponse.setHeader(JWT_HEADER_NAME, newToken); }
Filter
里,这样除了登陆入口,其它的业务代码将感受不到JWT的存在。WHITE_LIST
里,跳过对这些入口的验证。Payload
来生成一个新的JWT,这样新的JWT就会有新的过时时间,用此操做来刷新JWT,以防过时。Filter
,那么刷新的操做要在调用doFilter()
以前,由于调用以后就没法再修改response
了。private final static String JWT_HEADER_NAME = "Authorization"; @GetMapping("/api") public String testApi(HttpServletRequest request, HttpServletResponse response) { String oldJwt = request.getHeader(JWT_HEADER_NAME); String newJwt = response.getHeader(JWT_HEADER_NAME); return String.format("Your old JWT is:\n%s \nYour new JWT is:\n%s\n", oldJwt, newJwt); }
这时候API就处于JWT的保护下了。API能够彻底不用感知到JWT的存在,同时也能够主动获取JWT并解码,以获得JWT里的信息。如上所示。