赞
踩
全称:JSON Web Token(JSON Web令牌)
一个开放标准(RFC 7519) ,它定义了一种紧凑和自包含的方式, 用于作为 JSON 对象在各方之间安全地传输信息。此信息可以进行验证和信任,因为它是经过数字签名的。JWT 可以使用机密(使用 HMAC 算法)或使用 RSA 或 ECDSA 的公钥/私钥对进行签名。
虽然可以对 JWT 进行加密,以便在各方之间提供保密性,但是我们将关注已签名的Token。签名Token可以验证其中包含的声明的完整性,而加密Token可以向其他方隐藏这些声明。当使用公钥/私钥对对令牌进行签名时,该签名还证明只有持有私钥的一方才是对其进行签名的一方( 签名技术是保证传输的信息不被篡改,并不能保证信息传输的安全 )。
JWT最常见的场景就是授权认证,一旦用户登录之后,后续的每个请求都将包含JWT。系统在每次处理用户请求之前都要先通过JWT安全校验,通过之后再去进行处理。
解决了使用session的跨域问题
JWT由三部分组成,他们分别为:
在请求当中的出现形式为Header.Payload.Signature,如下:
<!--JWT(Json Web Token)登录支持-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
package com.liangtl.utils; import com.liangtl.dao.User; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import java.util.Date; import java.util.HashMap; import java.util.Map; @Component @ConfigurationProperties("jwt.data") public class JwtTokenUtil { private static final Logger LOGGER = LoggerFactory.getLogger(JwtTokenUtil.class); private static final String CLAIM_KEY_USERNAME = "sub"; private static final String CLAIM_KEY_CREATED = "created"; private String secret = "jwt-token-secret"; private Long expiration = 604800L; private String tokenHead = "Bearer"; /** * 根据负责生成JWT的token */ private String generateToken(Map<String, Object> claims) { return Jwts.builder() .setClaims(claims) .setExpiration(generateExpirationDate()) .signWith(SignatureAlgorithm.HS256, secret) .compact(); } /** * 从token中获取JWT中的负载 */ private Claims getClaimsFromToken(String token) { Claims claims = null; try { claims = Jwts.parser() .setSigningKey(secret) .parseClaimsJws(token) .getBody(); } catch (Exception e) { LOGGER.error("JWT格式验证失败:{}", token); } return claims; } /** * 生成token的过期时间 */ private Date generateExpirationDate() { return new Date(System.currentTimeMillis() + expiration * 1000); } /** * 从token中获取登录用户名 */ public String getUserNameFromToken(String token) { String username; try { Claims claims = getClaimsFromToken(token); username = claims.getSubject(); } catch (Exception e) { username = null; } return username; } /** * 验证token是否还有效 * * @param token 客户端传入的token * @param User 从数据库中查询出来的用户信息 */ public boolean validateToken(String token, User User) { String username = getUserNameFromToken(token); return username.equals(User.getUserName()) && !isTokenExpired(token); } /** * 判断token是否已经失效 */ private boolean isTokenExpired(String token) { Date expiredDate = getExpiredDateFromToken(token); return expiredDate.before(new Date()); } /** * 从token中获取过期时间 */ private Date getExpiredDateFromToken(String token) { Claims claims = getClaimsFromToken(token); return claims.getExpiration(); } /** * 根据用户信息生成token */ public String generateToken(User User) { Map<String, Object> claims = new HashMap<>(); claims.put(CLAIM_KEY_USERNAME, User.getUserName()); claims.put(CLAIM_KEY_CREATED, new Date()); return generateToken(claims); } /** * 当原来的token没过期时是可以刷新的 * * @param oldToken 带tokenHead的token */ public String refreshHeadToken(String oldToken) { if (StringUtils.isEmpty(oldToken)) { return null; } String token = oldToken.substring(tokenHead.length()); if (StringUtils.isEmpty(token)) { return null; } //token校验不通过 Claims claims = getClaimsFromToken(token); if (claims == null) { return null; } //如果token已经过期,不支持刷新 if (isTokenExpired(token)) { return null; } //如果token在30分钟之内刚刷新过,返回原token if (tokenRefreshJustBefore(token, 30 * 60 * 1000)) { return token; } else { claims.put(CLAIM_KEY_CREATED, new Date()); return generateToken(claims); } } /** * 判断token在指定时间内是否刚刚刷新过 * * @param token 原token * @param time 指定时间(秒) */ private boolean tokenRefreshJustBefore(String token, int time) { Claims claims = getClaimsFromToken(token); Date created = claims.get(CLAIM_KEY_CREATED, Date.class); Date refreshDate = new Date(); //刷新时间在创建时间的指定时间内 if (refreshDate.after(new Date(System.currentTimeMillis() - time)) && refreshDate.before(new Date())) { return true; } return false; } }
package com.liangtl.api; import com.liangtl.dao.User; import com.liangtl.framework.common.ResponseData; import com.liangtl.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/system") public class LoginController { @Autowired private UserService userService; @PostMapping("/login") public ResponseData login(@RequestBody User user) { return userService.login(user); } }
package com.liangtl.service.impl; import com.liangtl.dao.User; import com.liangtl.framework.common.ErrorCode; import com.liangtl.framework.common.ResponseData; import com.liangtl.framework.exception.TokenException; import com.liangtl.service.UserService; import com.liangtl.utils.JwtTokenUtil; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserServiceImpl implements UserService { @Autowired private JwtTokenUtil jwtTokenUtil; @Override public ResponseData login(User user) { if (user == null || StringUtils.isEmpty(user.getUserName()) || StringUtils.isEmpty(user.getPassword())) { throw new TokenException(ErrorCode.USER_ERROR_CODE, ErrorCode.USER_ERROR_MSG); } if ("admin".equals(user.getUserName()) && "123456".equals(user.getPassword())) { String token = jwtTokenUtil.generateToken(user); return ResponseData.success(token); } return ResponseData.failure(); } }
(tips:以上代码不完整,报错并非代码逻辑有问题而是有缺失类,如果完全copy的话需要适当调整使用)
。。。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。