我已经在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可以这样吗?如果是的话,怎么样?
答案 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"))
我猜测request
是HttpServletRequest
。
如果您未使用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)