【问题标题】:How to access HttpServletRequest or HttpSession in spring boot service componentspring boot服务组件中如何访问HttpServletRequest或HttpSession
【发布时间】:2021-03-15 03:52:53
【问题描述】:

我正在尝试在我的服务组件中访问 HttpServletRequestHttpSession。 服务组件是处理 github OAuth2 登录的地方。 以下是我的服务代码。

@RequiredArgsConstructor
@Service
public class GithubOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
    private final UserRepository userRepository;
    private final JwtTokenUtil jwtTokenUtil;
    private final HttpServletRequest request;

    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        OAuth2UserService<OAuth2UserRequest, OAuth2User> delegate = new DefaultOAuth2UserService();
        OAuth2User oAuth2User = delegate.loadUser(userRequest);

        String userNameAttributeName = userRequest.getClientRegistration()
                .getProviderDetails().getUserInfoEndpoint()
                .getUserNameAttributeName();

        OAuthAttributes attributes = OAuthAttributes.ofGithub(userNameAttributeName, oAuth2User.getAttributes());

        User user = saveOrFindUser(attributes);
       
        request.setAttribute("token", jwtTokenUtil.generateAccessToken(user.getId(), user.getRole()));

        return new DefaultOAuth2User(
                Collections.singleton(new SimpleGrantedAuthority(user.getRole().name())),
                attributes.getAttributes(),
                attributes.getNameAttributeKey()
        );
    }


    private User saveOrFindUser(OAuthAttributes attributes) {
        Optional<User> optionalUser = userRepository.findByEmail(attributes.getEmail());
        if(optionalUser.isPresent()) {
            return optionalUser.get();
        } else {
            return userRepository.save(attributes.toEntity());
        }
    }
}

下面是我的 Spring Security 配置类。

@RequiredArgsConstructor
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final GithubOAuth2UserService githubOAuth2UserService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .httpBasic().disable()
                .headers().frameOptions().disable()
                .and().csrf().disable()
                .cors().configurationSource(corsConfigurationSource())
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                    .authorizeRequests()
                        .antMatchers("/v1/health-check")
                        .permitAll()
                .and()
                    .logout()
                        .logoutSuccessUrl("/")
                .and()
                    .oauth2Login()
                        .successHandler(authenticationSuccessHandler())
                        .failureHandler(authenticationFailureHandler())
                        .userInfoEndpoint()
                        .userService(githubOAuth2UserService);
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.addAllowedOriginPattern("*");
        configuration.addAllowedHeader("*");
        configuration.addAllowedMethod("*");
        configuration.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    @Bean
    public AuthenticationFailureHandler authenticationFailureHandler() {
        return new GithubOAuthExceptionHandler();
    }

    @Bean
    public AuthenticationSuccessHandler authenticationSuccessHandler() {
        return new GithubOAuthOnSuccessHandler();
    }
}

我尝试使用 Lombok 的 @RequiredArgsConstructor 自动连接 HttpSessionHttpServletRequest,并尝试了以下方式。

HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

我收到以下错误。

java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

我正在尝试访问 @Service 组件中的 HttpServletRequestHttpSession,但我不明白为什么会发生此错误。 是否有任何额外的配置可以访问组件中的这些类? 我正在使用 Spring Boot 2.4.3。

【问题讨论】:

  • 试试这个answer在类似问题中讨论过。
  • 是的,但正如我上面提到的,类似问题的两个答案都对我不起作用。
  • 如果答案对您不起作用,我想知道 RequestContextFilter 是否在您的过滤器链中。过滤器在每个请求上填充RequestContextHolder

标签: spring-boot servlets spring-security oauth-2.0


【解决方案1】:

我通过使用评论的期望解决了这个问题。

答案是将RequestContextListener注册为spring配置类中的spring bean。

@SpringBootApplication
@EnableJpaAuditing
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public RequestContextListener requestContextListener() {
        return new RequestContextListener();
    }
}

【讨论】:

  • 在访问过滤阶段自动装配的当前请求的请求属性时,这对我有用。
【解决方案2】:

我知道这不是您提出的问题,但如果可以,我建议您将这项工作移至请求层。

很可能,User 对象中的值位于 SecurityContextHolder 中,以便可以在整个应用程序中访问它。

所以,首先,如果你像这样创建一个类:

static class MyOAuth2User extends User implements OAuth2User {
    public MyOAuth2User(User user, OAuthAttributes attributes) {
        super(user);
    }

    public Map<String, Object> getAttributes() {
        return this.attributes.getAttributes();
    }

    public String getName() {
        return getAttribute(this.attributes.getNameAttributeKey());
    }

    public Collection<? extends GrantedAuthority> getAuthorities() {
        return Collections.singleton(new SimpleGrantedAuthority(getRole().name()));
    }
}

那么,您的User 就可以成为安全主体的成员了。此外,它使您受益,因为您可以在您的 GitHubOAuthOnSuccessHandler 中访问它,您已经拥有 HttpServletRequest 对象:

public void onAuthenticationSuccess(...) {
    User user = (User) authentication.getPrincipal();
    String token = jwtTokenUtil.generateAccessToken(user.getId(), user.getRole());
    request.setAttribute("token", token);
    // ...
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-29
    • 1970-01-01
    • 2019-01-26
    • 1970-01-01
    • 2012-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多