Spring Webflux:帮助将代码转换为非阻塞

问题描述

在Spring Webflux应用程序中,我具有以下“ AuthenticationManager”实现。概括地说,以下是其要执行的操作-

  1. 某些url路径在prop文件中配置为需要基本身份验证,而其他则需要承载令牌。

  2. 对于基本身份验证,BcryptPasswordEncoder.matches方法用于将传入密码与存储在prop文件中的已编码密码进行比较。

  3. 对于承载令牌身份验证,正在使用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,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);).......

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)