繁体   English   中英

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

[英]Getting user info in java RESTful resource

我有一个基于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();
    }
}

覆盖SecurityContext

一种实现方法是在ContainerRequestFilter实现中重写ContainerRequestContextSecurityContext 可能是以下内容:

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

然后,可以使用@Context批注将SecurityContext注入任何资源类中:

@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) {
    ...
}

然后从SecurityContext获取Principal

Principal principal = securityContext.getUserPrincipal();
String username = principal.getName();

我最初在这个答案中描述了这种方法。

备择方案

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

  • 使用CDI,您可以创建一个带有@RequestScoped注释的bean,以保存已认证用户的名称。 执行认证之后,在请求范围的Bean中设置用户名称,然后使用@Inject将其注入资源类中。

  • 由于使用的是Spring,因此可以考虑在JAX-RS应用程序顶部使用Spring Security进行身份验证和授权。

我想您需要将SecurityContext作为参数添加到标注为@Context的方法中, @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();
}

暂无
暂无

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

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