向方法添加注释以记录是否允许运行

时间:2017-05-19 12:28:19

标签: java security annotations jersey

我已经在java中实现了自己的安全框架部分,但我遇到了一个小问题。

我希望能够检查用户是否有权访问某个方法。 我可以通过简单地在方法内部添加一个检查来完成此操作,如下所示:

@GET
public Response getResource() throws Exception
{
    if (AuthUtils.isAuthenticated(request, "ROLE1", "ROLE2"))
        return Response.ok("Hello World!").build();
    else
        return Response.status(HttpServletResponse.SC_UNAUTHORIZED).build();
}

您提供有权使用该功能的角色列表。

然而,在理想的世界中,我想做类似以下的事情

@Secure(roles = {"ROLE1", "ROLE"})
@GET
public Response getResource() throws Exception
{
    return Response.ok("Hello World!").build();
}

默认情况下,对使用@Secure注释的所有方法返回一个unathorized响应,其中用户没有正确的角色。

Java可以这样吗?如果是的话,怎么样?

3 个答案:

答案 0 :(得分:1)

如果您正在使用Jersey 2.x,请使用RolesAllowedDynamicFeature。您需要在申请中注册。这将处理授权。您将使用注释@RolesAllowed。它可以达到班级或方法水平

@RolesAllowed({"ROLE1", "ROLE"})
@GET
public Response getResource() throws Exception

如果您使用的是Servlet身份验证,则角色将填充在HttpServletRequest#getUserRoles中。在这里你不需要做任何其他事情。我假设servlet安全性是你从这段代码的外观中使用的

if (AuthUtils.isAuthenticated(request, "ROLE1", "ROLE2"))

我猜测requestHttpServletRequest

如果您未使用Servlet安全性,那么为了完成这项工作,您需要使用Jersey filter来设置SecurityContext。泽西岛将使用SecurityContext来检查角色。您可以在this post中看到一个示例。

另见:

答案 1 :(得分:1)

你需要做的是做一个方面,即。每次在调用特定“目标方法”之前调用的方法。你可以像前面提到的那样使用Spring,但你也可以使用Java core和Reflection来实现。为此,只有在用户具有正确的权限时,您才需要使用代理方法来调用实际的“目标方法”。或者,代理会抛出异常。所以这意味着您还需要使依赖注入动态化。

对于一个非常简单的应用程序,您甚至不需要注释。假设您想要保护对方法Service :: getSecuredResource:

的访问
public interface Service {
    Object getSecuredResource();
}

public class ServiceImpl implements Service {
    public Object getSecuredResource() {
        System.out.println("in my secure method");
        return "something private";
    }
}

public class ClientController {
    private Service service;     //line 1

    public void doSomething(){
        service.getSecuredResource();
    }

    public void setService(Service service)...
}

public final class AuthenticationService {

    public static void authenticate()...

    public static boolean isAuthenticated()...//do permission checks here
}

一个简单的解决方案是:

public class Main {
    public static void main(String[] args) {
        final ClientController clientController = new ClientController();

        injectDependencies(clientController);

        clientController.doSomething();
    }

    private static void injectDependencies(ClientController clientController) {       //line 2
        final Service serviceProxy = new Service() {
            private Service targetObject = new ServiceImpl();

            public Object getSecuredResource() {
                if (AuthenticationService.isAuthenticated()) {
                    return targetObject.getSecuredResource();
                }
                throw new SecurityException("you're not authorised");
            }
        };

        clientController.setService(serviceProxy);
    }
}

当然,如果你想要更动态的东西,你需要注释并使用Reflection创建动态代理并注入依赖项。 我会用我的自定义注释来注释服务声明(第1行),比如说MyInject。 然后Main :: injectDependencies方法(第2行)将替换为这样的东西:

   private static void injectDependencies(ClientController clientController) {
       Arrays.stream(clientController.getClass().getFields())
               .filter(field -> field.getAnnotation(MyInject.class)!=null)
               .forEach(field -> injectField(field, clientController));
   }

   private static void injectField(Field field, ClientController clientController) {
       InvocationHandler handler = new InvocationHandler() {
           @Override
           public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
               //verify here that the user has the right permissions for the called method
           }
       };
       Service serviceProxy = (Service) Proxy.newProxyInstance(
               Service.class.getClassLoader(),
               new Class[] { Service.class },
               handler);
       clientController.setService(serviceProxy);
   }

答案 2 :(得分:-1)

是的,可能。我们可以使用spring security plugin / library来做到这一点。 在春天我们可以关注Spring security 在Grails中我们可以关注Spring Security Plugin