jwt - Spring Webflux:帮助将代码转换为非阻塞
问题描述
在 Spring Webflux 应用程序中,我有以下“AuthenticationManager”实现。在高层次上,以下是它正在尝试做的事情 -
某些 url 路径在 prop 文件中配置为需要基本身份验证,而另一些则需要不记名令牌。
对于基本身份验证,BcryptPasswordEncoder.matches 方法用于将传入密码与存储在 prop 文件中的编码密码进行比较。
对于不记名令牌身份验证,正在使用 io.jsonwebtoken 库来验证令牌。
@Component public class AuthenticationManager implements ReactiveAuthenticationManager { /** The jwt util. */ @Autowired private JWTUtil jwtUtil; @Override public Mono<Authentication> authenticate(Authentication authobj) { return Mono.just(authobj).flatMap(authentication -> { String credentials = authentication.getCredentials().toString(); String path = authentication.getPrincipal().toString(); BasicAuthPath basicAuthPath = jwtUtil.isBasicAuthUrl(path); if (jwtUtil.isBasicScheme(credentials) || jwtUtil.isBearerScheme(credentials)) { if (jwtUtil.isBasicScheme(credentials) && basicAuthPath.isState()) { credentials = credentials.substring(5); if (jwtUtil.isBasicAuthSuccess(credentials.trim(), basicAuthPath.getPath())) { UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(credentials, null, null); return Mono.just(auth); } else { return Mono.empty(); } } else if (jwtUtil.isBearerTokenAuthUrl(path) && jwtUtil.isBearerScheme(credentials)) { credentials = credentials.substring(7); String username; try { username = jwtUtil.getUsernameFromToken(credentials); } catch (Exception e) { username = null; } if (jwtUtil.validateToken(credentials)) { Claims claims = jwtUtil.getAllClaimsFromToken(credentials); List<String> rolesMap = claims.get("role", List.class); List<Role> roles = new ArrayList<>(); for (String rolemap : rolesMap) { roles.add(Role.valueOf(rolemap)); } UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(username, null, roles.stream().map(authority -> new SimpleGrantedAuthority(authority.name())).collect(Collectors.toList())); return Mono.just(auth); } else { return Mono.empty(); } } else { return Mono.empty(); } } return Mono.empty(); }); } }
JwtUtil 代码如下
@Component
@Slf4j
public class JWTUtil implements Serializable {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 1L;
/** The env. */
@Autowired
private Environment env;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private JwtParser jwtParser;
@Autowired
private Key signingKey;
private static final PathPatternParser DEFAULT_PATTERN_PARSER = new PathPatternParser();
/**
* Checks if is basic auth success.
*
* @param inputCredentials the input credentials
* @param path the path
* @return true, if is basic auth success
*/
public boolean isBasicAuthSuccess(String inputCredentials, String path) {
String pathtoprop = pathtoprop(path);
String configpwd = env.getProperty(pathtoprop);
if (StringUtils.isBlank(configpwd)) {
configpwd = env.getProperty(pathtoprop.substring(0, pathtoprop.lastIndexOf(".")));
}
return passwordEncoder.matches(new String(Base64.getDecoder().decode(inputCredentials)), configpwd);
//return true;
}
/**
* Checks if is basic auth url.
*
* @param path the path
* @return true, if is basic auth url
*/
public BasicAuthPath isBasicAuthUrl(String path) {
BasicAuthPath basicAuthPath = new BasicAuthPath();
if (StringUtils.isNotBlank(env.getProperty("gateway.basicauth.urls"))) {
return pathMatcherBasic(StringUtils.split(env.getProperty("gateway.basicauth.urls"), ","), path);
}
basicAuthPath.setState(false);
return basicAuthPath;
}
/**
* pathMatcher
*
* @param pathPatterns
* @param path
* @return
*/
private BasicAuthPath pathMatcherBasic(String[] pathPatterns, String path) {
BasicAuthPath basicAuthPath = new BasicAuthPath();
for (String pathPattern : pathPatterns) {
PathPattern pattern = DEFAULT_PATTERN_PARSER.parse(pathPattern);
if (pattern.matches(PathContainer.parsePath(path))) {
basicAuthPath.setState(true);
basicAuthPath.setPath(pathPattern);
return basicAuthPath;
}
}
basicAuthPath.setState(false);
return basicAuthPath;
}
/**
* Checks if is bearer token auth url.
*
* @param path the path
* @return true, if is bearer token auth url
*/
public boolean isBearerTokenAuthUrl(String path) {
if (StringUtils.isNotBlank(env.getProperty("gateway.bearertoken.urls"))
&& pathMatcher(StringUtils.split(env.getProperty("gateway.bearertoken.urls"), ","), path)) {
return true;
}
return false;
}
/**
* pathMatcher
*
* @param pathPatterns
* @param path
* @return
*/
private boolean pathMatcher(String[] pathPatterns, String path) {
for (String pathPattern : pathPatterns) {
PathPattern pattern = DEFAULT_PATTERN_PARSER.parse(pathPattern);
if (pattern.matches(PathContainer.parsePath(path))) {
return true;
}
}
return false;
}
/**
* isBasicScheme
*
* @param credentials
* @return
*/
public boolean isBasicScheme(String credentials) {
if (StringUtils.isNotBlank(credentials) && credentials.startsWith(RestUriConstants.BASIC_TOKE_PREFIX)) {
return true;
}
return false;
}
/**
* isBearerScheme
*
* @param credentials
* @return
*/
public boolean isBearerScheme(String credentials) {
if (StringUtils.isNotBlank(credentials) && credentials.startsWith(RestUriConstants.BEARER_TOKE_PREFIX)) {
return true;
}
return false;
}
/**
* Gets the all claims from token.
*
* @param token the token
* @return the all claims from token
*/
public Claims getAllClaimsFromToken(String token) {
return jwtParser.parseClaimsJws(token).getBody();
}
/**
* Gets the username from token.
*
* @param token the token
* @return the username from token
*/
public String getUsernameFromToken(String token) {
return getAllClaimsFromToken(token).getSubject();
}
/**
* Gets the expiration date from token.
*
* @param token the token
* @return the expiration date from token
*/
public Date getExpirationDateFromToken(String token) {
return getAllClaimsFromToken(token).getExpiration();
}
/**
* Checks if is token expired.
*
* @param token the token
* @return the boolean
*/
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
/**
* Generate token.
*
* @param user the user
* @return the string
*/
public String generateToken(User user) {
Map<String, Object> claims = new HashMap<>();
claims.put("role", user.getRoles());
return doGenerateToken(claims, user.getUsername());
}
/**
* Do generate token.
*
* @param claims the claims
* @param username the username
* @return the string
*/
private String doGenerateToken(Map<String, Object> claims, String username) {
Long expirationTimeLong = Long.parseLong(env.getProperty("gateway.apollo.token.encryption.exp")); // in second
final Date createdDate = new Date();
final Date expirationDate = new Date(createdDate.getTime() + expirationTimeLong * 1000);
return Jwts.builder().setClaims(claims).setSubject(username).setIssuedAt(createdDate).setExpiration(expirationDate).signWith(signingKey)
.compact();
}
/**
* Validate token.
*
* @param token the token
* @return the boolean
*/
public Boolean validateToken(String token) {
Boolean result = false;
try {
result = !isTokenExpired(token);
} catch (Exception e) {
log.error("Exception in validateToken - {}",token);
}
return result;
}
private String pathtoprop(String path) {
return "gateway.basicauth.credentials" + path.replace('/', '.');
}
}
在使用大量并行线程完成 PST 期间,观察到高 CPU 利用率。我认为这可能是因为上面的很多代码都是阻塞的。如果这是真的,任何人都可以帮助提供有关如何以反应方式重构此代码的指针吗?我是否应该使用如下所示的线程池以获得更好的性能 -
Mono.just(authobj).publishOn(Schedulers.newParallel("password-encoder", Schedulers.DEFAULT_POOL_SIZE, true);).......
解决方案
推荐阅读
- java - 在 Spring Boot 应用程序中处理接口的具体实现中的重复代码
- plantuml - plantUML 语法中的嵌套 alt
- docker - 如何处理更改 docker compose 容器的 ips?
- reactjs - 在反应中使用 ag-grid
- bash - printf 以错误的顺序打印我的变量
- vb.net - vb .net 通过类传递对象/变量
- python - Python 将 yyyy-mm-dd 转换为 dd/mm/yyyy 但仍将列保留为 Excel 中的日期类型
- php - 我不明白为什么这个 php 函数不起作用
- css - 如何在 Safari 和 Safari 移动设备上使用 Bootstrap 4 设置高度?
- c++ - C ++:从向量的任何地方获取int