TLDR在我开发的Java Web应用程序中,需要实现对REST服务的用户区分。我知道有一些注释(@RolesAllowed
,@PermitAll
,@DenyAll
),可以描述哪个角色可以使用该服务。我的问题是,如何将角色@RolesAllowed
与用户角色枚举匹配,该用户是存储在数据库中的持久对象?
许多教程对进行了解释@RolesAllowed
,但是我发现没有一个与这些角色相匹配,而已经创建的
说明
如何通过自动检查用户角色(通过会话ID找到)来验证用户?我知道泽西岛已经通过注册完成此操作RolesAllowedDynamicFeature.class
。RolesAllowedDynamicFeature.class
通过将@DenyAll
注释放入方法中,我已经设法检查出它是否有效,并返回了403错误。
首先,让我们从一个用户开始。用户是数据库实体,Ebean
用于在Java对象之间持久存储它们。这是来自的样本User.class
:
/*
* A sample that describes the fields that I ask for and to understand the concept
*/
@Entity
@Table(name = "users")
public class User extends Model
{
@Id
@GeneratedValue
@Column(name = "id")
private long id;
@Enumerated(EnumType.STRING)
@Column(name = "role", nullable = false)
private UserRole role;
// contructors getters setters helper methods etc
/**
* Fetch a user from DB
*
* @param id the id to search for
* @return a Person.class object or may return null
*/
public static User getUserById(Long id)
{
return Ebean.find(User.class, id);
}
/* and here is the UserRole enum that define the roles every user can have */
public static enum UserRole
{
Administrator, User, Manager;
}
}
以上所有代码,工作正常,用户已正确存储,我可以轻松获取它们。
每个用户在登录时都会通过类似的服务进行身份验证,并为每个ConnectedUser对象创建一个唯一的会话ID(使用UUID)。在每个服务调用之后,将运行一个身份验证,该身份验证用户是否可以通过搜索来使用此服务,以及是否存在与此会话相关的用户条目(存储为cookie):
@Secured
@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter
{
@Context
private HttpServletRequest request;
/**
* Authenticates a user's access with every request that is made via a token.
*
* @param requestContext The request that is sent to the server.
* @throws IOException
*/
@Override
public void filter(ContainerRequestContext requestContext) throws IOException
{
boolean isValidated;
Cookie sessionCookie = null;
Cookie[] cookies = request.getCookies();
if (cookies.length != 0) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("CookieName")) {
sessionCookie = cookie;
}
}
}
if (sessionCookie != null) {
// UserValidationHandler checks if user is in connected_users table
isValidated = UserValidationHandler.validateUser(sessionCookie.getValue(), request.getRemoteAddr());
}
else {
MultivaluedMap pathParameters = requestContext.getUriInfo().getQueryParameters();
// UserValidationHandler checks if user is in connected_users table
isValidated = UserValidationHandler.validateUser((String)pathParameters.getFirst("token"), request.getRemoteAddr());
}
if (!isValidated) {
LOGGER.warn("[Authorization filter] Unauthorized user.");
URI indexURI = URI.create("http://login.jsp");
requestContext.setRequestUri(indexURI);
}
}
}
笔记:
注意1:大多数实现建议将角色应用到web.xml文件中。尽管对于我而言,这是不可行的。
注意2:另外,授权用户使用服务的正确位置在哪里?我发现可以使用创建ContainerRequestFilter
类@Priority(Priorities.AUTHORIZATION)
。哪个更好?
我有点在这里迷路了。我读了很多Q / A或样本,但是没有任何详尽的解释。
您应该将关注点分开,在一个过滤器中进行身份验证,在一个过滤器中进行授权。通常,如何完成此操作是通过SecurityContext
从身份验证过滤器内部设置,然后从授权过滤器内部检索它。
该SecurityContext
有isUserInRole
你覆盖方法。此方法应在授权过滤器中调用。通常,您将具有作为成员的角色SecurityContext
,并且仅对角色进行迭代
static class MySecurityContext implements SecurityContext {
private final String[] userRoles;
public MySecurityContext(String[] roles, String user) {
this.userRoles = roles;
}
@Override
public Principal getUser() {
return new Principal() {
@Override
public String getName() {
return name;
}
}
}
public boolean isUserInRole(String role) {
for (String userRole: userRoles) {
if (role.equals(userRole) {
return true;
}
}
return false;
}
// more methods to override
}
在身份验证过滤器中,您只需调用requestContext.setSecurityContext
传递new 的方法即可SecurityContext
。
在授权过滤器中,您可以@RolesAllowed
使用来获得注释ResourceInfo
。例如
class AuthorizationFilter implement ContainerRequestContext {
@Context
private ResourceInfo info;
@Override
public void filter(ContainerRequestContext request) {
SecurityContext sc = request.getSecurityContext();
RolesAllowed anno = info.getResourceMethod().getAnnotation(RolesAllowed.class);
String rolesAllowed = anno.value();
for (role: rolesAllowed) {
if (sc.isUserInRole(role)) {
return;
}
}
request.abortWith(Response.status(403).build());
}
}
或类似的规定。
但是,如果您使用的是Jersey2,则不需要自己实施授权。这已在中实现RolesAllowedDynamicFeature
。您只需要在应用程序中注册该功能。它的工作方式与我之前提到的相同。SecurityContext
预期在到达授权过滤器之前将A 填充,过滤器将检查角色并进行授权或拒绝。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句