使用 Spring Security 和 Auditing 时如何提高 JPA 批量插入的性能?

问题描述 投票:0回答:1

由于

@EnableJpaAuditing
注释,自定义
AuditorAware
类将被调用到
getCurrentAuditor()
,以便填充审核字段
lastCreatedBy
lastModifiedBy

@Component
@RequiredArgsConstructor
public class AuditorAwareImpl implements AuditorAware<User> {

    private final UserRepository userRepository;

    @Override
    public Optional<User> getCurrentAuditor() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return Optional.of(authentication)
                .map(Authentication::getName)
                .flatMap(userRepository::findByUsername);
    }
}

此类需要调用存储库才能获取该信息(从安全上下文中提取用户名/主体并获取用户)。

这在一次保存一个实体的情况下工作得很好,但是当使用

saveAll()
进行批量插入时,该操作会变成一个循环,以便为每个实体/行调用
getCurrentAuditor()

在拥有审计数据的同时实现高性能批量插入的最佳方法是什么?就我而言,我正在处理来自同一用户的批量导入,因此所有记录都将具有相同的审核值。

java spring spring-security audit
1个回答
0
投票

据我了解,您正在使用 Spring Security 资源服务器,因此您可以使用自定义声明转换器 在我的项目中我使用了以下配置

public SecurityFilterChain configure(HttpSecurity http) throws Exception {
    return http
            .authorizeHttpRequests(exchanges ->
                    exchanges
                            .requestMatchers("/v3/api-docs/**",
                                    "/v3/api-docs.yaml",
                                    "/swagger-ui/**",
                                    "/swagger-ui.html")
                                .permitAll()
                            .requestMatchers("/protected/**")
                                .authenticated())
            .csrf(httpSecurityCsrfConfigurer -> {
                httpSecurityCsrfConfigurer.disable();
            })
            .oauth2ResourceServer(oauth2ResourceServer -> oauth2ResourceServer.jwt(jwtConfigurer -> {
                jwtConfigurer.decoder(jwtDecoder());
            }))
            .headers(headerSpec -> {
                headerSpec.contentSecurityPolicy(contentSecurityPolicySpec -> {
                    contentSecurityPolicySpec.policyDirectives(
                                    "script-src 'strict-dynamic' 'nonce-rAnd0m123' 'unsafe-inline' http: https:;" +
                                    "default-src 'self'; "+
                                    "object-src 'none';" +
                                    "base-uri 'none';" +
                                    "require-trusted-types-for 'script';"
                    );
                }).xssProtection(xssProtectionSpec -> {
                    /*According to this https://docs.spring.io/spring-security/reference/features/exploits/headers.html#headers-xss-protection
                     and this https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-xss-protection
                     we need to disable X-XSS-Protection and give precedence to CSP https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#content-security-policy-csp
                     */
                    xssProtectionSpec.headerValue(XXssProtectionHeaderWriter.HeaderValue.DISABLED);
                });
            })
            .build();
}

@Bean

public BCryptPasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

// @Bean
public JwtDecoder jwtDecoder() {
    try {
        NimbusJwtDecoder decoder = JwtDecoders.fromOidcIssuerLocation(env.getProperty("issuer-uri"));
        decoder.setClaimSetConverter(new OauthSubClaimAdapter());
        return decoder;
    } catch (Exception e) {
        throw new IllegalStateException("Impossibile proseguire. Avvenuto errore nella creazione del jwtDecoder",
                e);
    }
}

虽然我的 OauthSubClaimAdapter 是:

public class OauthSubClaimAdapter implements Converter<Map<String, Object>, Map<String, Object>> {

  public static final String LOGGED_USER_INFO = "loggedUserInfo";
  private final MappedJwtClaimSetConverter delegate = MappedJwtClaimSetConverter.withDefaults(
      Collections.emptyMap());

  @Override
  public Map<String, Object> convert(Map<String, Object> claims) {
    Map<String, Object> convertedClaims = this.delegate.convert(claims);
    if (null == convertedClaims) {
      throw new IllegalStateException(
          String.format("Impossible continue; no converted claim found in %s",
              getClass().getName()));
    }
    String username = (String) convertedClaims.get("sub");
    //Here you can put your logic in order to enrich the user recovered from the JWT token
    convertedClaims.put(LOGGED_USER_INFO, enrichedUser);
    return convertedClaims;
  }
}

在您的身份验证对象中,您现在可以检索所有还包含 LOGGED_USER_INFO 对象的 JWT 声明

© www.soinside.com 2019 - 2024. All rights reserved.