繁体   English   中英

如何将当前的HttpServletRequest注入任何Spring服务?

[英]How to inject current HttpServletRequest into any Spring service?

我有一项服务,需要读取特殊的http查询参数。 因此,我必须以某种方式访问​​当前的HttpServletRequest 由于无法将请求作为参数传递,因此我必须以某种方式注入或读取它。

有两种可能性:从RequestContextHolder获取RequestContextHolder ,或直接注入HttpServletRequest 什么是正确的? 也许甚至还有第三种选择?

@Service
public class MyUserDetailsService implements UserDetailsService {
    //TODO is that correct? scope?
    @Autowired
    private HttpServletRequest req;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        req.getParameter("myparam");
   }
}

是线程安全的,因为MyUserDetailsService显然是单例的,而HttpServletRequest应该是@RequestScope吗?

我不知道您到底要训练什么,但是您需要知道:在服务类中使用HttpServletRequest时,您将遇到错误,因为servelet请求和类似Services的Spring组件位于不同的范围内,您不能当HttpServletRequest不在同一线程中时访问它。 我有几乎相同的问题,就我而言,我需要在JWT标头中获取用户ID并保存以进行一些查询。 因此,我在Spring Security链中创建了一个过滤器,并确实使用了SecurityContextHolder类。 这是我的代码:

@Slf4j
public class JWTAuthenticationFilter extends GenericFilterBean {

    private String enviroment;
    private JWTAuthenticationService jwtAuthenticationService;

    public JWTAuthenticationFilter(String enviroment,
                                   JWTAuthenticationService jwtAuthenticationService) {
        this.enviroment = enviroment;
        this.jwtAuthenticationService = jwtAuthenticationService;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {

        Claims jwtClaims = this.jwtAuthenticationService.getJWTClaims((HttpServletRequest) request);

        try {
            this.jwtAuthenticationService.checkJWT(enviroment, jwtClaims);
        } catch (UnauthorizedException ex){
            log.error("Token JWT Inválido");
            ((HttpServletResponse) response).sendError(401, ex.getMessage());
            return;
        }

        Authentication authentication = this.jwtAuthenticationService.getAuthentication(jwtClaims);

        SecurityContextHolder.getContext().setAuthentication(authentication);
        filterChain.doFilter(request, response);
    }
}


@Service
public class AuthRequestService {

  public String getAuthorizationKey() {
    Claims claims = (Claims)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    return claims.get(KEY_CLAIM).toString();
  }

}

通过这种方法,我避免了线程错误,因为我正在使用SecurityContextHolder管理器的当前上下文。

直接注入应该可以,但是它将是“请求范围”,而不是“会话范围”。

注入请求范围的Bean将导致创建代理。 从不是源自DispatcherServlet的线程访问该代理上的方法将导致IllegalStateException ,因为根据该代理没有可用的请求(实际上可能有零个或多个并发请求,但是无法确定性地绑定到一个)。 但是,当从实际上是HTTP请求的一部分的线程访问代理的方法时(在您的情况下,可能是在Controller-> Service中),它的行为就像是当前的HttpServletRequest

我不确定服务层是否是绑定HttpServletRequest的正确位置,尽管我不确定您的用例,但该服务可能是从其他异步上下文访问的。 无论如何,只要您的体系结构定义正确并且依赖于HttpServletRequest bean的类仅在请求线程/上下文中使用它,它就可以正常工作。

因此,总而言之,您应该做什么实际上取决于您的用例。 听起来您只会从DispatcherServlet内部访问它,因此很安全,但是也许您应该抽象化(分开考虑)将数据获取到另一个提供给Service类的类。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM