我正在尝试将自己的身份验证和授权添加到Java EE REST应用程序中。我已经设法使用JAX-RS的SecurityContext
,ContainerRequestFilter
实现(使用JWT)和端点方法的@RolesAllowed
注释。但我需要EJB,他们根本不使用JAX-RS的SecurityContext(无论用户角色如何,我都得EJBAccessException
),所以我需要另一种解决方案。
EJB中有SecurityContext
这样的东西可以实现吗?或者我应该使用像Shiro这样的图书馆?我想从应用程序本身管理用户,因此不能选择容器或LDAP提供的用户管理。我正在使用JPA对用户进行身份验证和授权。
所以,主要问题是:
如何基于JAX-RS过滤器在EJB中使用自己的身份验证和基于角色的授权机制(使用@RolesAllowed注释)?如何告诉EJB请求是否相关具有这些角色的具体认证用户?
还有一件事 - 我宁愿避免特定于供应商的解决方案,但如果必须,我会选择JBoss / Wildfly。
答案 0 :(得分:2)
您当前的解决方案是否正确设置了min_sphere = {(x_i,r_i) : from POI_min},
spheres_to_cover = {(x_i,r_i) : from POI_max}
A = {}
while not is_empty(spheres_to_cover)
power_set_score = struct // holds score, k
PS <- costruct power set of sphere_to_cover
for i = 1:number_of_elements(PS)
k = PS[i]
if intersection(k) \ min_sphere is not empty
power_set_score[i].score = |k|
else
power_set_score[i].score = 0
end if
power_set_score[i].k = k
end for
sort(power_set_score) // sort by score, biggest first
A <- add arbitrary point in (intersection(power_set_score[1].k) \ min_sphere)
spheres_to_cover = spheres_to_cover \ power_set_score[1].k
end while
个对象?它是Java EE安全的核心,包括EJB。
通常,您需要一个支持JPA和自定义身份验证方法的auth + IDM解决方案; PicketLink可能是您的选择。不幸的是,现在据说PicketLink被KeyCloak取代,我个人认为这是一个有争议的决定。 KeyCloak不提供应用内IDM - 它是一项重要的功能,而且它正是您所寻找的。 p>
JSR 375: Java™ EE Security API是一种新兴规范,将以标准的,与供应商无关的方式解决上述所有问题。 Soteria是JSR 375 RI。目前,它只支持只读身份存储。
答案 1 :(得分:1)
我会说你会在REST Api上使用HTTP身份验证标头,这将由Container的配置验证。将会有一个特定于供应商的具体实现,因为还没有Java EE供应商中立规范。验证用户后,将创建Principal
并且所有EJB @RolesAllowed注释都将起作用。
我已移植DukesForest to Wildfly,因此您可以看到它的实例。查看dukes-payment for rest service,请注意web.xml和jboss-web.xml。另外,请查看实体项目以获取数据库配置:
基本上,web.xml将定义安全约束:
<security-constraint>
<web-resource-collection>
<web-resource-name>Secure payment service</web-resource-name>
<description/>
<url-pattern>/*</url-pattern>
<http-method-omission>GET</http-method-omission>
</web-resource-collection>
<auth-constraint>
<role-name>USERS</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
<security-role>
<role-name>USERS</role-name>
</security-role>
Wildfly需要添加security-domain
来指定如何查询数据库:
<security-domain name="dukes-forest" cache-type="default">
<authentication>
<login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag="required">
<module-option name="dsJndiName" value="java:jboss/ForestXADS"/>
<module-option name="rolesQuery" value="select NAME as 'ROLES', 'Roles' as 'ROLEGROUP' from forest.GROUPS g inner join forest.PERSON_GROUPS pg on g.ID = pg.GROUPS_ID join forest.PERSON p on p.EMAIL = pg.EMAIL where p.EMAIL = ?"/>
<module-option name="hashAlgorithm" value="MD5"/>
<module-option name="hashEncoding" value="HEX"/>
<module-option name="principalsQuery" value="select PASSWORD from forest.PERSON where EMAIL=?"/>
</login-module>
</authentication>
<authorization>
<policy-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag="required">
<module-option name="dsJndiName" value="java:jboss/ForestXADS"/>
<module-option name="rolesQuery" value="select NAME as 'ROLE', 'ROLES' as 'ROLEGROUP' from forest.GROUPS g inner join forest.PERSON_GROUPS pg on g.ID = pg.GROUPS_ID join forest.PERSON p on p.EMAIL = pg.EMAIL where p.EMAIL = ?"/>
<module-option name="hashAlgorithm" value="MD5"/>
<module-option name="hashEncoding" value="HEX"/>
<module-option name="principalsQuery" value="select PASSWORD from forest.PERSON where EMAIL=?"/>
</policy-module>
</authorization>
</security-domain>
这是基本的想法。
PS&GT;还有一个Java Security Quickstart Archetype在Web框架中实现安全性,并且应该很容易根据上面的示例添加Http Basic Authentication。
答案 2 :(得分:1)
我一直在研究这个问题并最终得到了我自己的解决方案。它是在JAX-RS
接口级别实施的(由Pradeep Pati建议) - 因此,如果您需要通过EJB
访问您的bean,它将无效。
因此,正如我发现here,ContainerRequestFilter
可以访问资源方法(或类)注释,所以我需要做的就是:
<强> 1。实现我自己的@RolesAllowed
注释:
@Inherited
@Target( {ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RolesAllowed {
String[] value();
}
<强> 2。使用自定义身份验证和授权实施ContainerRequestFilter
:
@Provider
@Priority(Priorities.AUTHENTICATION)
public class SecurityFilter implements ContainerRequestFilter {
@Context
private ResourceInfo resourceInfo;
@Override
public void filter(ContainerRequestContext context) throws IOException {
// here we have access to headers:
String authorizationHeader = context.getHeaderString("Authorization");
// and, thanks to injected resourceInfo, to annotations:
RolesAllowed annotation = resourceInfo
.getResourceClass() // or getResourceMethod(), I've used both
.getAnnotation(RolesAllowed.class);
// and, finally, to the roles (after a null-check)
String[] roles = annotation.value();
// then you can authenticate and authorize everything on your own using any method (I’ve used Basic Auth and JWT)
// and, if something fails, you can abort the request:
if (!isAuthenticated) {
context.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
} else if (!isAuthorized) {
context.abortWith(Response.status(Response.Status.FORBIDDEN).build());
}
}
...
}
然而,我已经评估了Avishai的解决方案(使用 PicketLink )。虽然这有点难以实现,有时可能很复杂(例如基本的JPA场景需要大约7-8个JPA实体),但如果您需要具有大量选项的可靠,可扩展的安全系统(如LDAP或JPA,或者甚至两者同时)或具有各种身份验证选项(例如同时使用Basic和JWT auth,但具有不同的头文件)。关于这个话题可能有数百个优点和/或缺点,所以这不是一个简单的选择。
有趣的是,PicketLink使用它自己的@org.picketlink.authorization.annotations.RolesAllowed
注释而不是javax.annotation
注释。不过,它应该适用于EJB
次调用,因为它使用EJB
拦截器而不是JAX-RS
过滤器来检查角色。
但对我而言,这似乎是一种矫枉过正,所以我提出了自己的,不那么复杂(但有效)的解决方案。
答案 3 :(得分:0)
我在apache shiro上构建了一个库,以支持java ee中的身份验证和授权
https://github.com/panchitoboy/shiro-jwt
您可以在测试文件夹中看到一个示例。
此致