在java RESTful资源中获取用户信息

在java RESTful资源中获取用户信息,java,rest,security,Java,Rest,Security,我有一个基于Rest的服务,使用ContianerRequestFilter(下面是AuthFilter)来验证用户或其令牌。当用户被授权或未按预期授权时,该级别的所有内容都可以正常工作。问题是如何在资源层获取用户信息?例如,如果用户请求区域资源(以下)中的区域列表,我如何获取用户信息并使用该信息约束结果返回给他/她 AuthFilter: @Provider @PreMatching public class AuthFilter implements ContainerRequestFilt

我有一个基于Rest的服务,使用ContianerRequestFilter(下面是AuthFilter)来验证用户或其令牌。当用户被授权或未按预期授权时,该级别的所有内容都可以正常工作。问题是如何在资源层获取用户信息?例如,如果用户请求区域资源(以下)中的区域列表,我如何获取用户信息并使用该信息约束结果返回给他/她

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();
    }
}

我想您需要将
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或具有某些名称的(会话)属性(例如
user.security.ctx
),并以相同的方式插入请求。i、 e

@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();
}

我想您需要将
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或具有某些名称的(会话)属性(例如
user.security.ctx
),并以相同的方式插入请求。i、 e

@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();
}
覆盖
SecurityContext
实现它的一种可能方法是在实现中重写。它可以是以下内容:

requestContext.setSecurityContext(新的SecurityContext(){
@凌驾
公共主体getUserPrincipal(){
返回新主体(){
@凌驾
公共字符串getName(){
返回用户名;
}
};
}
@凌驾
公共布尔值isUserInRole(字符串角色){
返回true;
}
@凌驾
公共布尔值isSecure(){
返回false;
}
@凌驾
公共字符串getAuthenticationScheme(){
返回null;
}
});
然后,可以使用注释将注入到任何资源类中:

@Path(“/示例”)
公共类MyResource{
@上下文
私有SecurityContext SecurityContext;
...
}
它还可以注入到资源方法参数中:

@GET
@路径(“/{id}”)
@产生(MediaType.APPLICATION_JSON)
公共响应myResourceMethod(@PathParam(“id”)长id,
@上下文安全上下文(SecurityContext){
...
}
然后从以下位置获取:

Principal=securityContext.getUserPrincipal();
字符串username=principal.getName();
我最初在本文中描述了这种方法

选择

如果由于某种原因不想重写,则可以考虑其他方法,取决于应用程序中可用的内容:

  • 使用CDI,您可以创建一个带注释的bean来保存经过身份验证的用户的名称。在执行身份验证之后,在请求范围bean中设置用户的名称,并使用将其注入到资源类中

  • >P>因为您使用Spring,您可以考虑在JAX-RS应用程序的顶部使用Spring Security进行身份验证和授权。

覆盖
SecurityContext
实现它的一种可能方法是在实现中重写。它可以是以下内容:

requestContext.setSecurityContext(新的SecurityContext(){
@凌驾
公共主体getUserPrincipal(){
返回新主体(){
@凌驾
公共字符串getName(){
返回用户名;
}
};
}
@凌驾
公共布尔值isUserInRole(字符串角色){
返回true;
}
@凌驾
公共布尔值isSecure(){
返回false;
}
@凌驾
公共字符串getAuthenticationScheme(){
返回null;
}
});
然后,可以使用注释将注入到任何资源类中:

@Path(“/示例”)
公共类MyResource{
@上下文
私有SecurityContext SecurityContext;
...
}
它还可以注入到资源方法参数中:

@GET
@路径(“/{id}”)
@产生(MediaType.APPLICATION_JSON)
公共响应myResourceMethod(@PathParam(“id”)长id,
@上下文安全上下文(SecurityContext){
...
}
然后从以下位置获取:

Principal=securityContext.getUserPrincipal();
字符串username=principal.getName();
我最初在本文中描述了这种方法

选择

如果由于某种原因不想重写,则可以考虑其他方法,取决于应用程序中可用的内容:

  • 使用CDI,您可以创建一个带注释的bean来保存经过身份验证的用户的名称。在执行身份验证之后,在请求范围bean中设置用户的名称,并使用将其注入到资源类中

  • >P>因为您使用Spring,您可以考虑在JAX-RS应用程序的顶部使用Spring Security进行身份验证和授权。


感谢凯西奥和瓦迪姆的回答。这对我来说效果最好,因为我已经过度使用了SecurityContext。将@Context SecurityContext SecurityContext设为参数就成功了。@superTorthed我很高兴知道它起了作用。请别忘了更新我们的答案:)很高兴听到它起作用。BTX将其作为方法参数注入总是更好。将其作为实例变量要求资源类为@RequestScope,以避免多线程问题。多亏了Cassio和Vadim的回答。这对我来说效果最好,因为我已经过度使用了SecurityContext。将@Context SecurityContext SecurityContext设为参数就成功了。@superTorthed我很高兴知道它起了作用。求你了,别忘了向上看