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;
}
}
SpringCloud Alibaba Security安全认证的更多相关文章
- springCloud Alibaba服务的注册与发现之eureka搭建
1.创建eureka微服务模块.导入maven依赖. <dependency> <groupId>org.springframework.cloud</groupId&g ...
- SpringCloud Alibaba微服务实战 - 基础环境准备
Springcloud Aibaba现在这么火,我一直想写个基于Springcloud Alibaba一步一步构建微服务架构的系列博客,终于下定决心从今天开始本系列文章的第一篇 - 基础环境准备. 该 ...
- SpringCloud Alibaba微服务实战一 - 基础环境准备
Springcloud Aibaba现在这么火,我一直想写个基于Springcloud Alibaba一步一步构建微服务架构的系列博客,终于下定决心从今天开始本系列文章的第一篇 - 基础环境准备. 该 ...
- Spring Cloud实战 | 第九篇:Spring Cloud整合Spring Security OAuth2认证服务器统一认证自定义异常处理
本文完整代码下载点击 一. 前言 相信了解过我或者看过我之前的系列文章应该多少知道点我写这些文章包括创建 有来商城youlai-mall 这个项目的目的,想给那些真的想提升自己或者迷茫的人(包括自己- ...
- 最简单易懂的Spring Security 身份认证流程讲解
最简单易懂的Spring Security 身份认证流程讲解 导言 相信大伙对Spring Security这个框架又爱又恨,爱它的强大,恨它的繁琐,其实这是一个误区,Spring Security确 ...
- SpringCloud Alibaba微服务实战三 - 服务调用
导读:通过前面两篇文章我们准备好了微服务的基础环境并让accout-service 和 product-service对外提供了增删改查的能力,本篇我们的内容是让order-service作为消费者远 ...
- SpringCloud Alibaba 简介
SpringCloud Aliababa简介 SpringCloud Alibaba是阿里巴巴集团开源的一套微服务架构解决方案. 微服务架构是为了更好的分布式系统开发,将一个应用拆分成多个子应用,每一 ...
- SpringCloud Alibaba (一):序言
为什么要转用SpringCloud Alibaba? Spring Cloud Netflix项目进入维护模式 在2018年底时,Netflix宣布Hystrix进入维护模式.自2016年以来,Rib ...
- SpringCloud Alibaba (三):Sentinel 流量控制组件
SpringCloud Alibaba (三):Sentinel 流量控制组件 Sentinel 是什么 随着微服务的流行,服务和服务之间的稳定性变得越来越重要.Sentinel 是面向分布式服务架构 ...
- SpringCloud Alibaba (四):Dubbo RPC框架
Dubbo简介 Apache Dubbo |ˈdʌbəʊ| 是一款高性能.轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现.致 ...
随机推荐
- ElasticSearch之cat templates API
命令样例如下: curl -X GET "https://localhost:9200/_cat/templates?v=true&pretty" --cacert $ES ...
- ElasticSearch之cat aliases API
执行aliases命令,如下: curl -X GET "https://localhost:9200/_cat/aliases?pretty&v=true" --cace ...
- Python——第四章:作用域
作用域: 变量的访问权限 全局变量 -> 全局作用域 局部变量 -> 局部作用域(比如在函数内定义的变量,只能在函数内调用) a = 10 # 全局变量 -> 全局作用域 print ...
- MySQL|MySQL事物以及隔离级别
MySQL 事务主要用于处理操作量大,复杂度高的数据.比如开单,需要添加给订单表增加记录,还需要增加订单的各种相关明细,操作复杂度高,这些操作语句需要构成一个事务.在 MySQL 命令行的默认设置下, ...
- CSS3学习笔记-句子排版效果
CSS3提供了丰富的排版效果,可以通过样式属性来控制文本的排列方式.字体样式.行高.字间距等.以下是一些常用的句子排版效果示例: 文本对齐方式: .text-center { text-align: ...
- Vue 2 和 Vue 3 中 toRefs的区别
摘要:本文将介绍 Vue 2 和 Vue 3 中 toRefs 函数的不同用法和行为,并解释其在各个版本中的作用. 正文: Vue 是一款流行的 JavaScript 框架,用于构建用户界面.在 Vu ...
- java中获取公网IP
package com.dashan.utils.iputils; import org.apache.commons.lang.StringUtils; import java.io.Buffere ...
- vue上传文件显示进度条,当上传完成后间隔一秒进度条消失
<template> <el-upload class="avatar-uploader" action="api/file/upload" ...
- 再拔头筹,FusionInsight为华为云大数据打造硬实力
摘要:在IDC2020大数据报告中,有云服务厂商.传统ICT 厂商,以及大数据时代的创企等三类"玩家",为何华为云能够脱颖而出? 近日,IDC发布<IDC MarketS ...
- Win10 企业版激活方法
如果大家想要激活 Win10的企业版,可以依次执行下面的命令,分别表示安装win10企业版密钥,设置kms服务器,激活win10企业版;slmgr /ipk NW6C2-QMPVW-D7KKK-3GK ...