3

我有一个 Spring bean,它需要来自请求的信息,但不直接从控制器调用(虽然它可能是 - 但我想在没有它的情况下尝试这个)

基本上,我的 API 通过 thrift 向其他服务发出请求。当它发出请求时,会有这样的服务调用:

authenticationService.authenticate(null, "username", "password");

第一个参数(null)通常是请求上下文的“占位符”实例。请求上下文包含有关发出请求的用户、发起 IP 等的信息。这样,我可以获得有关原始调用者的所有详细信息,而不会让我的 API 基础架构泄漏到后端。

但是,要做到这一点,我有一个InvocationHandler拦截对我的服务接口代理进行的方法调用。在该代理处理程序内部,我有一个RequestContextFactory创建RequestContext. 在这个工厂内部,我需要从请求中获取信息。特别是SecurityContext,所以我可以识别拨打电话的用户。

现在,我有:

@Provider
@Component
public class WebRequestContextFactory implements RequestContextFactory {
    @Context private ContainerRequest containerRequest;

    public RequestContext createRequestContext() {

    }
}

不幸的是,containerRequest总是null

4

4 回答 4

2

您可以使用ServletRequestAttributes从 获取信息,request并且ServletRequestAttributes可以从 获取信息RequestContextHolder

ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
                .currentRequestAttributes();

如果请求由 Spring 处理DispatcherServlet,则不需要任何特殊设置。DispatcherServlet已经暴露了所有相关状态。但是如果请求是在 Spring 之外处理的DispatcherServlet,那么您需要javax.servlet.ServletRequestListener在应用程序的 web.xml 文件中添加:

    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>

这会将请求与当前线程相关联,然后可以通过 检索相关的请求属性RequestContextHolder

于 2013-09-24T08:25:18.550 回答
0

对于身份验证,最好使用容器领域,或者使用普通的 servlet。

对于授权,您可以使用 Application 或 rest servlet。在这种过程中,您可以从上下文注释中找到信息。这是示例:

(@Context final SecurityContext sc, @Context Request request) {
        logMe(sc);
...
    }

    private void logMe(final SecurityContext sc) {
        try {
            LOGGER.info("User=" + sc.getUserPrincipal().getName());
            LOGGER.info("User Role?=" + sc.isUserInRole("user"));
            LOGGER.info("Auth way=" + sc.getAuthenticationScheme());
        } catch (final Exception e) {
            LOGGER.debug(e);
        }
    }

或者:

(@Context final SecurityContext sc, @Context ContainerRequestContext request) {
...
于 2013-09-23T14:34:00.240 回答
0

您可以创建一个访问令牌,其中包含您想要的信息,例如 IP 地址、用户名等。在身份验证阶段创建一个自定义令牌并将此令牌放入 Spring 安全上下文中。稍后您可以从代理类中的其他地方提取此令牌。提取您验证的令牌或任何您想要的令牌后。

创建自定义对象和令牌:

public class CustomAuthentication {

  private String userId;

  private String password;

  private String ipAddress;
}


public class CustomAuthenticationToken extends AbstractAuthenticationToken {

    private CustomAuthentication customAuthentication;

    public CustomAuthenticationToken(MobiLabAuthentication authentication,
      Collection<? extends GrantedAuthority> authorities) {
      super(authorities);
      this.customAuthentication = authentication;
      setAuthenticated(true);
    }

    public CustomAuthenticationToken() {
      super(null);
      setAuthenticated(false);
    }

    @Override
    public Object getCredentials() {
     return customAuthentication.getPassword();
    }

    @Override
    public Object getPrincipal() {
      return customAuthentication.getUserId();
    }

}

将令牌存储到 Spring 安全上下文中

List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new RestUserAuthrity("YOUR_APP_ROLE"));

//Extract IP , user and pass etc and construct CustomAuthentication instance
CustomAuthentication authentication = new CustomAuthentication(.....)

CustomAuthenticationToken authenticationToken = new CustomAuthenticationToken(
     authentication, authorities);

SecurityContextHolder.getContext().setAuthentication(authenticationToken);

验证来自 Proxy bean 的安全信息

SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();

if (authentication instanceof CustomAuthenticationToken) {
  CustomAuthenticationToken token = (CustomAuthenticationToken) authentication;
 //now you can get your ip address from token
}
于 2013-09-24T19:25:50.807 回答
0

在稍微不同的情况下,以下内容对我有用。YMMV。

替换这个:

@Context private ContainerRequest containerRequest;

有了这个:

@Context private javax.inject.Provider<ContainerRequest> containerRequestProvider;

然后在你的代码中你需要的地方ContainerRequest

ContainerRequest containerRequest = containerRequestProvider.get();

将我指向此解决方案的代码示例:https ://github.com/psamsotha/jersey-okhttp-interceptor-demo/blob/b3b2da00b284e75011ea780fb37b555ea581ac96/src/main/java/com/example/stackoverflow/client/UserFactory.java

于 2019-12-19T11:40:46.523 回答