我有一个基于Rest的服务,使用ContianerRequestFilter(下面的AuthFilter)来验证用户或他们的令牌。当用户被授权或未按预期授权时,该级别的所有内容都可以正常工作。问题是如何获取资源层中的用户信息?例如,如果用户请求AreasResource(下面)中的区域列表,我如何获取用户信息并使用它来约束结果返回给他/她?
AuthFilter筛选:
@Provider
@PreMatching
public class AuthFilter implements ContainerRequestFilter
{
@Autowired
IAuthenticator authenticator;
@Override
public void filter(ContainerRequestContext requestContext) throws IOException
{
//PUT, POST, GET, DELETE...
String method = requestContext.getMethod();
String path = requestContext.getUriInfo().getPath(true);
UserWrapper authenticationResult = null;
Date expireTime = new Date(new Date().getTime() + 60 * 1000);
if (!"init".equals(path))
{
if ("GET".equals(method) && ("application.wadl".equals(path) || "application.wadl/xsd0.xsd".equals(path)))
{
return;
}
String auth = requestContext.getHeaderString("authorization");
if(auth == null)
{
throw new WebApplicationException(Status.UNAUTHORIZED);
}
if (auth.startsWith("Bearer"))
{
String token = auth.substring("Bearer".length()).trim();
try
{
authenticationResult = validateToken(token);
}
catch (Exception e)
{
throw new WebApplicationException(Status.UNAUTHORIZED);
}
}
else
{
//lap: loginAndPassword
String[] lap = BasicAuth.decode(auth);
if (lap == null || lap.length != 2)
{
throw new WebApplicationException(Status.UNAUTHORIZED);
}
// Handle authentication validation here
authenticationResult = authenticator.authenticatUser(lap);
// if null then user can't be found or user name and password failed
if (authenticationResult == null)
{
throw new WebApplicationException(Status.UNAUTHORIZED);
}
}
}
else
{
authenticationResult = new UserWrapper(new User(), expireTime.getTime());
}
// We passed so we put the user in the security context here
String scheme = requestContext.getUriInfo().getRequestUri().getScheme();
requestContext.setSecurityContext(new ApplicationSecurityContext(authenticationResult, scheme));
}
private UserWrapper validateToken(String token) throws Exception
{
UserWrapper userWrapper = AuthenticatorCache.getInstance().getObj(token);
if (userWrapper == null)
{
throw new Exception("No session found");
}
return userWrapper;
}
}
区域资源:
@Path("/areas")
@Component
@Api(value = "/areas" )
public class AreasResource implements IAreas
{
@Override
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response listActiveAreas() {
return Response.ok('woo hoo it worked').build();
}
}
答案 0 :(得分:3)
SecurityContext
实现它的一种可能方法是覆盖SecurityContext
实施中ContainerRequestContext
的ContainerRequestFilter
。它可能是以下内容:
requestContext.setSecurityContext(new SecurityContext() {
@Override
public Principal getUserPrincipal() {
return new Principal() {
@Override
public String getName() {
return username;
}
};
}
@Override
public boolean isUserInRole(String role) {
return true;
}
@Override
public boolean isSecure() {
return false;
}
@Override
public String getAuthenticationScheme() {
return null;
}
});
然后可以使用SecurityContext
注释在任何资源类中注入@Context
:
@Path("/example")
public class MyResource {
@Context
private SecurityContext securityContext;
...
}
它可以在资源方法参数中注入:
@GET
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON)
public Response myResourceMethod(@PathParam("id") Long id,
@Context SecurityContext securityContext) {
...
}
然后从Principal
获取SecurityContext
:
Principal principal = securityContext.getUserPrincipal();
String username = principal.getName();
我最初在此answer中描述了这种方法。
如果您因某些原因不想覆盖SecurityContext
,可以考虑其他方法,具体取决于您的应用中可用的内容:
使用CDI,您可以创建一个使用@RequestScoped
注释的bean来保存经过身份验证的用户的名称。执行身份验证后,在请求范围的bean中设置用户的名称,并使用@Inject
将其注入资源类。
由于您使用的是Spring,因此可以考虑在JAX-RS应用程序的顶部使用Spring Security进行身份验证和授权。
答案 1 :(得分:1)
我想您需要将SecurityContext
作为参数添加到注释为@Context
的方法中,如下所示:
@Override
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response listActiveAreas(@Context SecurityContext securityCtx) {
// Do something with data in securityCtx...
return Response.ok("woo hoo it worked").build();
}
如果它不起作用(我没有尝试并使用其他方式):
您可以将securityContext设置为具有某个名称的HttpRequest / HttpServletRequest或(Session)属性(例如user.security.ctx
)并以相同方式注入Request。即。
@Override
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response listActiveAreas(@Context HttpServletRequest request) {
SecurityContext securityCtx = (SecurityContext )request.getAttribute("user.security.ctx");
// Do something with data in securityCtx...
return Response.ok("woo hoo it worked").build();
}