我有一个需要来自请求的信息的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
。
答案 0 :(得分:1)
您可以使用ServletRequestAttributes
从request
获取信息,ServletRequestAttributes
可以从RequestContextHolder
获取信息:
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
.currentRequestAttributes();
如果请求由Spring DispatcherServlet
处理,则无需任何特殊设置。 DispatcherServlet
已经暴露了所有相关的州。但是如果请求是在Spring的DispatcherServlet
之外处理的,那么您需要在应用程序的web.xml文件中添加javax.servlet.ServletRequestListener
:
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
这会将请求与当前线程相关联,然后可以通过RequestContextHolder
检索关联的请求属性。
答案 1 :(得分:0)
对于身份验证,最好使用容器领域,或者使用普通的servlet。
对于Authorization,您可以使用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) {
...
答案 2 :(得分: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
}
答案 3 :(得分:0)
在稍微不同的情况下,以下内容对我有用。 YMMV。
替换此:
@Context private ContainerRequest containerRequest;
与此:
@Context private javax.inject.Provider<ContainerRequest> containerRequestProvider;
然后在代码中需要ContainerRequest
的位置:
ContainerRequest containerRequest = containerRequestProvider.get();