自定义筛选器被调用两次

2cmtqfgy  于 2021-07-14  发布在  Java
关注(0)|答案(1)|浏览(390)

这个问题在这里已经有了答案

注册为Springbean时过滤调用两次(1个应答)
10天前关门了。
我使用okta在springboot-rest(ful)api资源服务器中处理身份验证和授权。我从他们提供的一个例子开始。为了处理用户,我实现了一个过滤器来存储包含 uid 在每个请求之前声明,因为我的应用程序的每个路由都需要身份验证。以下是过滤器的代码:

@Component
@RequiredArgsConstructor
public class AppUserRegistrationFilter extends OncePerRequestFilter {

    private final AppUserService appUserService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        JwtAuthenticationToken jwtAuthenticationToken = (JwtAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();

        appUserService.checkAppUserRegistration(jwtAuthenticationToken);

        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }
}

以下是web配置类的代码:

@Configuration
@RequiredArgsConstructor
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    private final AppUserService appUserService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .oauth2ResourceServer()
                .jwt();
        http
                .cors();
        http
                .addFilterAfter(new AppUserRegistrationFilter(appUserService), BearerTokenAuthenticationFilter.class);

        Okta.configureResourceServer401ResponseBody(http);
    }

}

这个 AppUserRepository 没有什么特别的,只是延伸 JpaRepository<AppUser, Long> 以及 AppUser 是包含uid和email字符串以及注册和上次访问时间的两个localdatetime字段的实体。最后,以下是appuserservice实现类中方法的代码:

@Override
public void checkAppUserRegistration(JwtAuthenticationToken jwtAuthenticationToken) {
    String uid = (String) jwtAuthenticationToken.getTokenAttributes().get("uid");
    Optional<AppUser> appUserOptional = appUserRepository.findByUid(uid);
    LocalDateTime now = LocalDateTime.now();
    // By default, the name maps to the sub claim according to Spring Security docs
    String email = jwtAuthenticationToken.getName();
    if (appUserOptional.isEmpty()) {
        AppUser newUser = AppUser.builder()
                .uid(uid)
                .email(email)
                .registrationDateTime(now)
                .lastAccessDateTime(now)
                .build();
        appUserRepository.save(newUser);
    } else {
        AppUser appUser = appUserOptional.get();
        if (!appUser.getEmail().equals(email)) {
            // User changed email address, update accordingly
            appUser.setEmail(email);
        }
        appUser.setLastAccessDateTime(now);
        appUserRepository.save(appUser);
    }
}

如果我启动前端应用程序,就是这个,我用我从okta开发者 Jmeter 板创建的用户登录,然后我检查“消息”部分,在后端,我看到用户创建正确,但随后过滤器立即再次调用,如果我检查数据库,我看到注册日期和最后访问日期不同。
为什么过滤器会被调用两次?这是正常行为吗?

zdwk9cvp

zdwk9cvp1#

springboot将自动注册任何扩展的springbean Filter 使用servlet容器。
请参阅spring引导文档:
将servlet、过滤器和侦听器注册为springbean
任何 Servlet , Filter, 或servlet *Listener 作为springbean的示例在嵌入式容器中注册。
自从你的 AppUserRegistrationFilter 类被注解为 @Component ,spring将自动为类创建一个单例bean,因此它将自动注册到servlet容器中。
当你打电话的时候 http.addFilterAfter(new AppUserRegistrationFilter(appUserService), BearerTokenAuthenticationFilter.class); ,您将手动创建该类的另一个示例,并使用servlet容器手动注册过滤器。
因此,您的代码同时注册了该类的两个不同示例。
解决方法:不要打电话 addFilterAfter() 或移除 @Component 注解。

相关问题