JsonWebToken工具结合切面token实现认证
权限校验的控制---1,直接用权限框架
2,用路径特征---不同的controller用不同的路径前缀---可根据这种特征用不同的权限认证
用JsonWebToken工具hash需要的字段之后生成一段字符串,之后这段字符串可以反向获取之前的明文----这个可以作为token--可以翻译出信息的token
用一个切面结合token实现认证:----尤其外部分享链接可以采用这种方式
1,认证
2,验证是否有效
有效期:每次请求之后无论成功失败都刷新,每次刷新都是重新生成claim除了用户名,密码,还是有事件戳,所以每次生成的不一样
if (!tokenUtils.validateToken(token, user)) {
log.info("{} : token validation fails", request.getServletPath());
response.setStatus(HttpCodeEnum.FORBIDDEN.getCode());
response.getWriter().print("Invalid token ");
return false;
}
/**
* 根据 用户名、密码 验证 token
*
* @param token
* @param username
* @param password
* @return
*/
public Boolean validateToken(String token, String username, String password) {
String tokenUsername = getUsername(token);
String tokenPassword = getPassword(token);
return (username.equals(tokenUsername) && password.equals(tokenPassword) && !(isExpired(token)));
}
认证:
@Override
public User shareLogin(String token, UserLogin userLogin) throws NotFoundException, ServerException, UnAuthorizedExecption {
//AES解密
String decrypt = AESUtils.decrypt(token, null);
//获取分享信息
String tokenUserName = tokenUtils.getUsername(decrypt);
String tokenPassword = tokenUtils.getPassword(decrypt);
String[] tokenInfos = tokenUserName.split(Constants.SPLIT_CHAR_STRING);
String[] tokenCrypts = tokenPassword.split(Constants.SPLIT_CHAR_STRING);
if (tokenInfos.length < 2) {
throw new ServerException("Invalid share token");
}
User loginUser = userMapper.selectByUsername(userLogin.getUsername());
if (null == loginUser) {
throw new NotFoundException("user is not found");
}
//校验密码
if (!BCrypt.checkpw(userLogin.getPassword(), loginUser.getPassword())) {
throw new ServerException("password is wrong");
}
Long shareUserId = Long.parseLong(tokenInfos[1]);
if (shareUserId.longValue() < 1L) {
throw new ServerException("Invalid share token");
}
User shareUser = userMapper.getById(shareUserId);
if (null == shareUser) {
throw new ServerException("Invalid share token");
}
if (tokenInfos.length == 3) {
if (tokenCrypts.length < 2) {
throw new ServerException("Invalid share token");
}
try {
String sharedUserName = tokenInfos[2];
Long sharedUserId = Long.parseLong(tokenCrypts[1]);
if (!(loginUser.getUsername().equals(sharedUserName) && loginUser.getId().equals(sharedUserId)) && !loginUser.getId().equals(shareUserId)) {
throw new ForbiddenExecption("The resource requires authentication, which was not supplied with the request");
}
} catch (NumberFormatException e) {
throw new ForbiddenExecption("The resource requires authentication, which was not supplied with the request");
}
}
//是否激活
if (!loginUser.getActive()) {
throw new ServerException("this user is not active");
}
return loginUser;
}
验证是否失效:
/**
* 修改dashboard下的widget关联信息
*
* @param bindingResult
* @param user
* @param request
* @return
*/
@ApiOperation(value = "update dashboard widget relation")
@PutMapping(value = "/{portalId}/dashboards/widgets", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity updateMemDashboardWidget(@PathVariable("portalId") Long portalId,
@Valid @RequestBody MemDashboardWidgetDto[] memDashboardWidgets,
@ApiIgnore BindingResult bindingResult,
@ApiIgnore @CurrentUser User user,
HttpServletRequest request) {
if (bindingResult.hasErrors()) {
ResultMap resultMap = new ResultMap(tokenUtils).failAndRefreshToken(request).message(bindingResult.getFieldErrors().get(0).getDefaultMessage());
return ResponseEntity.status(resultMap.getCode()).body(resultMap);
}
for (MemDashboardWidget memDashboardWidget : memDashboardWidgets) {
if (invalidId(memDashboardWidget.getId())) {
ResultMap resultMap = new ResultMap(tokenUtils).failAndRefreshToken(request).message("Invalid id");
return ResponseEntity.status(resultMap.getCode()).body(resultMap);
}
if (invalidId(memDashboardWidget.getDashboardId())) {
ResultMap resultMap = new ResultMap(tokenUtils).failAndRefreshToken(request).message("Invalid dashboard id");
return ResponseEntity.status(resultMap.getCode()).body(resultMap);
}
if (invalidId(memDashboardWidget.getWidgetId())) {
ResultMap resultMap = new ResultMap(tokenUtils).failAndRefreshToken(request).message("Invalid widget id");
return ResponseEntity.status(resultMap.getCode()).body(resultMap);
}
if (memDashboardWidget.getPolling() && memDashboardWidget.getFrequency() < 1) {
ResultMap resultMap = new ResultMap(tokenUtils).failAndRefreshToken(request).message("Invalid frequency");
return ResponseEntity.status(resultMap.getCode()).body(resultMap);
}
}
dashboardService.updateMemDashboardWidgets(portalId, user, memDashboardWidgets);
return ResponseEntity.ok(new ResultMap(tokenUtils).successAndRefreshToken(request));
}
生成token的时候如果需要使用过期时间,刷新也就是重新设置过期时间然后重新生成
可以不用过期时间,生成永久的token
一般用于生成token的明文的对象是map类型
/**
* 根据 TokenDetail 实体生成Token
*
* @param tokenDetail
* @return
*/
public String generateToken(TokenDetail tokenDetail) {
Map<String, Object> claims = new HashMap<String, Object>();
claims.put(Consts.TOKEN_USER_NAME, StringUtils.isEmpty(tokenDetail.getUsername()) ? EMPTY : tokenDetail.getUsername());
claims.put(Consts.TOKEN_USER_PASSWORD, StringUtils.isEmpty(tokenDetail.getPassword()) ? EMPTY : tokenDetail.getPassword());
claims.put(Consts.TOKEN_CREATE_TIME, System.currentTimeMillis());
return generate(claims);
}
/**
* 根据 clams生成token
*
* @param claims
* @return
*/
private String generate(Map<String, Object> claims) {
Long expiration = Long.parseLong(claims.get(Consts.TOKEN_CREATE_TIME) + EMPTY) + TIMEOUT;
try {
return Jwts.builder()
.setClaims(claims)
.setSubject(claims.get(Consts.TOKEN_USER_NAME).toString())
.setExpiration(new Date(expiration))
.signWith(null != SignatureAlgorithm.valueOf(ALGORITHM) ?
SignatureAlgorithm.valueOf(ALGORITHM) :
SignatureAlgorithm.HS512, SECRET.getBytes("UTF-8"))
.compact();
} catch (UnsupportedEncodingException ex) {
log.warn(ex.getMessage());
return Jwts.builder()
.setClaims(claims)
.setSubject(claims.get(Consts.TOKEN_USER_NAME).toString())
.setExpiration(new Date(expiration))
.signWith(null != SignatureAlgorithm.valueOf(ALGORITHM) ?
SignatureAlgorithm.valueOf(ALGORITHM) :
SignatureAlgorithm.HS512, SECRET)
.compact();
}
}
解析token,生成claims对象,后续用这个对象获取相应的属性(明文)
/**
* 获取token claims
*
* @param token
* @return
*/
private Claims getClaims(String token) {
Claims claims;
try {
claims = Jwts.parser()
.setSigningKey(SECRET.getBytes("UTF-8"))
.parseClaimsJws(token.startsWith(Consts.TOKEN_PREFIX) ?
token.substring(token.indexOf(Consts.TOKEN_PREFIX) + Consts.TOKEN_PREFIX.length()).trim() :
token.trim())
.getBody();
} catch (Exception e) {
log.warn(e.getMessage());
claims = Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token.startsWith(Consts.TOKEN_PREFIX) ?
token.substring(token.indexOf(Consts.TOKEN_PREFIX) + Consts.TOKEN_PREFIX.length()).trim() :
token.trim())
.getBody();
}
return claims;
}
/**
* 解析 token 用户名
*
* @param token
* @return
*/
public String getUsername(String token) {
String username;
try {
final Claims claims = getClaims(token);
username = claims.get(Consts.TOKEN_USER_NAME).toString();
} catch (Exception e) {
username = null;
}
return username;
}
上一篇: 工程师 - 谈谈PHP程序员的职业规划?