SpringCloud Alibaba Security安全认证
一、 Security配置(auth认证中心)
代码地址
https://github.com/typ1805/blog-cloud
Spring Security是一套安全框架,可以基于RBAC(基于角色的权限控制)对用户的访问权限进行控制。
添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
</dependency>
1、WebSecurityConfig
登录认证授权等主要采用Spring security + JWT,首先配置WebSecurityConfig,Redis配置主要是为了满足需:
- 当用户的角色或者权限变动后
- 已获授权的用户需要重新登录授权
package com.blog.config;
import com.blog.jwt.JWTAuthenticationEntryPoint;
import com.blog.jwt.JWTAuthenticationFilter;
import com.blog.jwt.JWTAuthorizationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
/**
* @path:com.blog.config.WebSecurityConfig.java
* @className:WebSecurityConfig.java
* @description:Security配置
* @author:tanyp
* @dateTime:2020/11/9 16:31
* @editNote:
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("userDetailsServiceImpl")
private UserDetailsService userDetailsService;
@Autowired
private StringRedisTemplate redisTemplate;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(new JWTAuthenticationFilter(authenticationManager(), redisTemplate), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JWTAuthorizationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling().authenticationEntryPoint(new JWTAuthenticationEntryPoint());
}
}
2、UserDetailsServiceImpl
通过用户名去查找用户及拥有的角色和权限
package com.blog.service;
import com.blog.domain.AuthUser;
import com.blog.common.core.constants.Constants;
import com.blog.common.core.constants.JWTConstants;
import com.blog.common.core.result.Wrapper;
import com.blog.provider.UserProvider;
import com.blog.vo.MenuVo;
import com.blog.vo.RoleVo;
import com.blog.vo.UserVo;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @path:com.blog.service.impl.UserDetailsServiceImpl.java
* @className:UserDetailsServiceImpl.java
* @description:自定义用户认证和授权
* @author:tanyp
* @dateTime:2020/11/9 15:44
* @editNote:
*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@DubboReference
private UserProvider userProvider;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Wrapper<UserVo> userInfo = userProvider.findByUsername(username);
if (userInfo.getCode() != Constants.SUCCESS) {
throw new UsernameNotFoundException("用户:" + username + ",不存在!");
}
Set<SimpleGrantedAuthority> grantedAuthorities = new HashSet<>();
UserVo userVo = new UserVo();
BeanUtils.copyProperties(userInfo.getResult(), userVo);
Wrapper<List<RoleVo>> roleInfo = userProvider.getRoleByUserId(String.valueOf(userVo.getId()));
if (roleInfo.getCode() == Constants.SUCCESS) {
List<RoleVo> roleVoList = roleInfo.getResult();
for (RoleVo role : roleVoList) {
// 角色必须是ROLE_开头,可以在数据库中设置
SimpleGrantedAuthority grantedAuthority = new SimpleGrantedAuthority(JWTConstants.ROLE_PREFIX + role.getValue());
grantedAuthorities.add(grantedAuthority);
// 获取权限
Wrapper<List<MenuVo>> menuInfo = userProvider.getRolePermission(String.valueOf(role.getId()));
if (menuInfo.getCode() == Constants.SUCCESS) {
List<MenuVo> permissionList = menuInfo.getResult();
for (MenuVo menu : permissionList) {
if (!StringUtils.isEmpty(menu.getUrl())) {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(menu.getUrl());
grantedAuthorities.add(authority);
}
}
}
}
}
AuthUser user = new AuthUser(userVo.getUsername(), userVo.getPassword(), grantedAuthorities);
user.setId(userVo.getId());
return user;
}
}
3、JWTAuthorizationFilter
主要对用户进行认证工作,当登录时,获取用户名和密码,通过authenticationManager.authenticate,最终会调用UserDetailsServiceImpl来获取用户信息(在DaoAuthenticationProvider的retrieveUser中),
然后在DaoAuthenticationProvider的additionalAuthenticationChecks中校验密码。
package com.blog.jwt;
import com.alibaba.fastjson.JSONObject;
import com.blog.domain.AuthUser;
import com.blog.common.core.constants.JWTConstants;
import com.blog.common.core.result.WrapMapper;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.crypto.MACVerifier;
import com.nimbusds.jwt.SignedJWT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.StringUtils;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.ParseException;
import java.util.Date;
/**
* @path:com.blog.jwt.JWTAuthorizationFilter.java
* @className:JWTAuthorizationFilter.java
* @description:授权
* @author:tanyp
* @dateTime:2020/11/19 13:19
* @editNote:
*/
@Slf4j
public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
public JWTAuthorizationFilter(AuthenticationManager authenticationManager) {
super(authenticationManager);
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String token = request.getHeader(JWTConstants.TOKEN_HEADER);
if (StringUtils.isEmpty(token) || !token.startsWith(JWTConstants.TOKEN_PREFIX)) {
chain.doFilter(request, response);
return;
}
try {
Authentication authentication = getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
onSuccessfulAuthentication(request, response, authentication);
chain.doFilter(request, response);
} catch (Exception e) {
e.printStackTrace();
onUnsuccessfulAuthentication(request, response, new AccountExpiredException(e.getMessage()));
}
}
@Override
protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException {
log.info("=============Token 验证成功=================");
}
@Override
protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException {
log.error("================token校验失败=======================");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("UTF-8");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write(JSONObject.toJSONString(WrapMapper.error(HttpServletResponse.SC_UNAUTHORIZED, failed.getMessage())));
}
/**
* @methodName:getAuthentication
* @description:这里从token中获取用户信息并新建一个token
* @author:tanyp
* @dateTime:2020/11/19 13:37
* @Params: [tokenHeader]
* @Return: org.springframework.security.authentication.UsernamePasswordAuthenticationToken
* @editNote:
*/
private UsernamePasswordAuthenticationToken getAuthentication(String tokenHeader) throws ParseException, JOSEException {
String token = tokenHeader.replace(JWTConstants.TOKEN_PREFIX, "");
SignedJWT jwt = SignedJWT.parse(token);
JWSVerifier verifier = new MACVerifier(JWTConstants.SECRET);
// 校验是否有效
if (!jwt.verify(verifier)) {
throw new AccountExpiredException(JWTConstants.TOKEN_INVALID);
}
// 校验超时
Date expirationTime = jwt.getJWTClaimsSet().getExpirationTime();
if (new Date().after(expirationTime)) {
throw new AccountExpiredException(JWTConstants.TOKEN_EXPIRE);
}
// 获取载体中的数据
Object account = jwt.getJWTClaimsSet().getClaim("payload");
if (account != null) {
AuthUser user = JSONObject.parseObject(account.toString(), AuthUser.class);
return new UsernamePasswordAuthenticationToken(user.getUsername(), null, user.getAuthorities());
}
return null;
}
}
4.JWTAuthenticationFilter
在JWTAuthenticationFilter中,把权限信息等写入到了redis中。
只要后台权限变动的时候,根据key的规则清除redis数据即可, 然后在gateway中获取不到相应的权限, 那么会要求用户重新登录。
package com.blog.jwt;
import com.alibaba.fastjson.JSONObject;
import com.blog.common.core.constants.JWTConstants;
import com.blog.common.core.constants.RedisConstants;
import com.blog.common.core.enums.AuthEnum;
import com.blog.common.core.result.WrapMapper;
import com.blog.common.core.result.Wrapper;
import com.blog.common.core.utils.JWTUtiles;
import com.blog.common.core.utils.Md5Utils;
import com.blog.domain.AuthUser;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
* @path:com.blog.jwt.JWTAuthenticationFilter.java
* @className:JWTAuthenticationFilter.java
* @description:权限变动重新授权
* @author:tanyp
* @dateTime:2020/11/19 13:15
* @editNote:
*/
@Slf4j
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
private StringRedisTemplate redisTemplate;
public JWTAuthenticationFilter(AuthenticationManager authenticationManager, StringRedisTemplate redisTemplate) {
this.authenticationManager = authenticationManager;
this.redisTemplate = redisTemplate;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
String username = request.getParameter("username");
String password = request.getParameter("password");
return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
}
@SneakyThrows
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
AuthUser user = (AuthUser) authResult.getPrincipal();
// 生成token
String payload = JSONObject.toJSONString(user);
String jwtToken = JWTUtiles.createToken(payload);
// 生成Key, 把权限放入到redis中
String keyPrefix = RedisConstants.TOKEN_KEY_PREFIX + user.getId() + ":";
String keySuffix = Md5Utils.getMD5(jwtToken.getBytes());
String key = keyPrefix + keySuffix;
String authKey = key + RedisConstants.AUTH_KEY;
redisTemplate.opsForValue().set(key, jwtToken, JWTConstants.EXPIRE_TIME, TimeUnit.MILLISECONDS);
redisTemplate.opsForValue().set(authKey, JSONObject.toJSONString(user.getAuthorities()), JWTConstants.EXPIRE_TIME, TimeUnit.SECONDS);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("UTF-8");
response.getWriter().write(JSONObject.toJSONString(WrapMapper.success().result(jwtToken)));
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
log.error("========登录认证失败:", failed);
Wrapper result = null;
int status = AuthEnum.AUTH_NO_TOKEN.getKey();
if (failed instanceof UsernameNotFoundException) {
result = WrapMapper.error(AuthEnum.AUTH_NONEXISTENT.getKey(), AuthEnum.AUTH_NONEXISTENT.getValue());
} else if (failed instanceof BadCredentialsException) {
result = WrapMapper.error(AuthEnum.AUTH_NO_TOKEN.getKey(), AuthEnum.AUTH_NO_TOKEN.getValue());
}
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("UTF-8");
response.setStatus(status);
response.getWriter().write(JSONObject.toJSONString(result));
}
}
注: 主要是生成JWT的token, 并且把权限信息放入redis。
登录直接调用Security框架的login方法即可
格式:
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0IiwicGF5bG9hZCI6IntcImFjY291bnROb25FeHBpcmVkXCI6dHJ1ZSxcImFjY291bnROb25Mb2NrZWRcIjp0cnVlLFwiYXV0aG9yaXRpZXNcIjpbe1wiYXV0aG9yaXR5XCI6XCJcL21zcy11cG1zXC9vcmRlclwvbGlzdFwifSx7XCJhdXRob3JpdHlcIjpcIlwvbXNzLXVwbXNcL29yZGVyXC9kZXRhaWxcIn0se1wiYXV0aG9yaXR5XCI6XCJST0xFX2FkbWluXCJ9XSxcImNyZWRlbnRpYWxzTm9uRXhwaXJlZFwiOnRydWUsXCJlbmFibGVkXCI6dHJ1ZSxcImlkXCI6NDgsXCJwYXNzd29yZFwiOlwiJDJhJDEwJHZtcC56V1duWDNMRnhTczZJMDBpMGV1cmxIUjd5bWNmVVE1SHRYdzcxdzlRSi4ySlVmOFVhXCIsXCJ1c2VybmFtZVwiOlwiYWRtaW5cIn0iLCJleHAiOjE2MDYxMzA4MDd9.Wb-2UkAcVrj4KbQteT6D9RbktXgkPLI-tB5ymMkqsjI
二、网关校验(gateway模块)
网关的主要作用是对JWT和具体的URL进行校验,校验不通过则返回错误信息,主要通过AuthGlobalFilter来实现。
1、AuthGlobalFilter
package com.blog.filter;
import com.alibaba.fastjson.JSON;
import com.blog.common.core.constants.JWTConstants;
import com.blog.common.core.constants.RedisConstants;
import com.blog.common.core.enums.AuthEnum;
import com.blog.common.core.result.WrapMapper;
import com.blog.common.core.utils.JWTUtiles;
import com.blog.common.core.utils.Md5Utils;
import com.blog.config.ExclusionUrlConfig;
import com.blog.vo.Authority;
import com.blog.vo.UserVo;
import com.nimbusds.jwt.SignedJWT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.text.ParseException;
import java.util.List;
/**
* @path:com.blog.filter.AuthGlobalFilter.java
* @className:AuthGlobalFilter.java
* @description:token过滤器
* @author:tanyp
* @dateTime:2020/11/10 18:06
* @editNote:
*/
@Slf4j
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
@Autowired
private ExclusionUrlConfig exclusionUrlConfig;
AntPathMatcher antPathMatcher = new AntPathMatcher();
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
String headerToken = request.getHeaders().getFirst(JWTConstants.TOKEN_HEADER);
log.info("headerToken:{}", headerToken);
// 只要带上了token, 就需要判断Token是否有效
if (!StringUtils.isEmpty(headerToken) && !JWTUtiles.verifierToken(headerToken)) {
return getVoidMono(response, AuthEnum.AUTH_NO_TOKEN.getKey(), AuthEnum.AUTH_NO_TOKEN.getValue());
}
String path = request.getURI().getPath();
log.info("request path:{}", path);
// 判断是否是过滤的路径, 是的话就放行
if (isExclusionUrl(path)) {
return chain.filter(exchange);
}
// 判断请求的URL是否有权限
boolean permission = hasPermission(headerToken, path);
if (!permission) {
return getVoidMono(response, AuthEnum.AUTH_NO_ACCESS.getKey(), AuthEnum.AUTH_NO_ACCESS.getValue());
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
private Mono<Void> getVoidMono(ServerHttpResponse response, int i, String msg) {
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
response.setStatusCode(HttpStatus.OK);
byte[] bits = JSON.toJSONString(WrapMapper.error(i, msg)).getBytes();
DataBuffer buffer = response.bufferFactory().wrap(bits);
return response.writeWith(Mono.just(buffer));
}
private boolean isExclusionUrl(String path) {
List<String> exclusions = exclusionUrlConfig.getUrl();
if (exclusions.size() == 0) {
return false;
}
return exclusions.stream().anyMatch(action -> antPathMatcher.match(action, path));
}
/**
* @methodName:hasPermission
* @description:判断请求的URL是否有权限
* @author:tanyp
* @dateTime:2020/11/24 9:38
* @Params: [headerToken, path]
* @Return: boolean
* @editNote:
*/
private boolean hasPermission(String headerToken, String path) {
try {
if (StringUtils.isEmpty(headerToken)) {
return false;
}
SignedJWT jwt = JWTUtiles.getSignedJWT(headerToken);
Object payload = jwt.getJWTClaimsSet().getClaim("payload");
UserVo user = JSON.parseObject(payload.toString(), UserVo.class);
// 生成Key, 把权限放入到redis中
String keyPrefix = RedisConstants.TOKEN_KEY_PREFIX + user.getId() + ":";
String token = headerToken.replace(JWTConstants.TOKEN_PREFIX, "");
String keySuffix = Md5Utils.getMD5(token.getBytes());
String key = keyPrefix + keySuffix;
String authKey = key + RedisConstants.AUTH_KEY;
String authStr = redisTemplate.opsForValue().get(authKey);
if (StringUtils.isEmpty(authStr)) {
return false;
}
List<Authority> authorities = JSON.parseArray(authStr, Authority.class);
return authorities.stream().anyMatch(authority -> antPathMatcher.match(authority.getAuthority(), path));
} catch (ParseException e) {
e.printStackTrace();
}
return false;
}
}
2、白名单配置(ExclusionUrlConfig)
package com.blog.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @path:com.blog.config.ExclusionUrlConfig.java
* @className:ExclusionUrlConfig.java
* @description:白名单配置
* @author:tanyp
* @dateTime:2020/11/19 14:01
* @editNote:
*/
@Data
@Component
@ConfigurationProperties(prefix = "exclusion")
public class ExclusionUrlConfig {
private List<String> url;
}
配置信息
# 配置白名单路径
exclusion:
url:
- /auth/checkUser
- /auth/login
三、相关工具类
1、JWT
package com.blog.common.core.utils;
import com.blog.common.core.constants.JWTConstants;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import lombok.extern.slf4j.Slf4j;
import java.text.ParseException;
import java.util.Date;
/**
* @path:com.blog.common.core.utils.JWTUtiles.java
* @className:JWTUtiles.java
* @description:JWT工具类
* @author:tanyp
* @dateTime:2020/11/24 9:32
* @editNote:
*/
@Slf4j
public class JWTUtiles {
/**
* @methodName:createToken
* @description:创建token
* @author:tanyp
* @dateTime:2020/11/24 10:20
* @Params: [user]
* @Return: java.lang.String
* @editNote:
*/
public static String createToken(String payload) throws JOSEException {
// 创建密钥
MACSigner macSigner = new MACSigner(JWTConstants.SECRET);
// payload
JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
.subject("subject")
.claim("payload", payload)
.expirationTime(new Date(System.currentTimeMillis() + JWTConstants.EXPIRE_TIME))
.build();
JWSHeader jwsHeader = new JWSHeader(JWSAlgorithm.HS256);
// 创建签名的JWT
SignedJWT signedJWT = new SignedJWT(jwsHeader, claimsSet);
signedJWT.sign(macSigner);
// 生成token
String jwtToken = signedJWT.serialize();
return jwtToken;
}
/**
* @methodName:verifierToken
* @description:验证token
* @author:tanyp
* @dateTime:2020/11/24 9:35
* @Params: [headerToken]
* @Return: boolean
* @editNote:
*/
public static boolean verifierToken(String headerToken) {
try {
SignedJWT jwt = getSignedJWT(headerToken);
JWSVerifier verifier = new MACVerifier(JWTConstants.SECRET);
// 校验是否有效
if (!jwt.verify(verifier)) {
log.error("token不合法,检测不过关");
return false;
}
// 校验超时
Date expirationTime = jwt.getJWTClaimsSet().getExpirationTime();
if (new Date().after(expirationTime)) {
log.error("token已经过期");
return false;
}
// 获取载体中的数据
return true;
} catch (ParseException | JOSEException e) {
log.error("token校验出错", e);
}
return false;
}
public static SignedJWT getSignedJWT(String headerToken) throws ParseException {
String token = headerToken.replace(JWTConstants.TOKEN_PREFIX, "");
log.info("token is {}", token);
return SignedJWT.parse(token);
}
}
2、MD5加密
package com.blog.common.core.utils;
import java.io.UnsupportedEncodingException;
/**
* @path:com.blog.common.core.utils.Md5Utils.java
* @className:Md5Utils.java
* @description:MD5加密
* @author:tanyp
* @dateTime:2020/11/9 15:31
* @editNote:
*/
public class Md5Utils {
private static final int HEX_VALUE_COUNT = 16;
public static String getMD5(byte[] bytes) {
char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
char[] str = new char[16 * 2];
try {
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
md.update(bytes);
byte[] tmp = md.digest();
int k = 0;
for (int i = 0; i < HEX_VALUE_COUNT; i++) {
byte byte0 = tmp[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
} catch (Exception e) {
e.printStackTrace();
}
return new String(str);
}
public static String getMD5(String value, String encode) {
String result = "";
try {
result = getMD5(value.getBytes(encode));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return result;
}
}