将@RolesAllowed注释应用于数据库中存储的现有用户

SkoD:

TLDR在我开发的Java Web应用程序中,需要实现对REST服务的用户区分。我知道有一些注释(@RolesAllowed@PermitAll@DenyAll),可以描述哪个角色可以使用该服务。我的问题是,如何将角色@RolesAllowed与用户角色枚举匹配,该用户是存储在数据库中的持久对象?

许多教程对进行了解释@RolesAllowed,但是我发现没有一个与这些角色相匹配,而已经创建的


说明

如何通过自动检查用户角色(通过会话ID找到)来验证用户?我知道泽西岛已经通过注册完成此操作RolesAllowedDynamicFeature.classRolesAllowedDynamicFeature.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或样本,但是没有任何详尽的解释。

保罗·萨姆索塔(Paul Samsotha):

您应该将关注点分开,在一个过滤器中进行身份验证,在一个过滤器中进行授权通常,如何完成此操作是通过SecurityContext从身份验证过滤器内部设置,然后从授权过滤器内部检索它。

SecurityContextisUserInRole你覆盖方法。此方法应在授权过滤器中调用。通常,您将具有作为成员的角色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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如果您有一个Firebase快照,并且将过滤器应用于当前用户的孩子,那么该如何对数据库中的所有用户执行此操作?

更新数据库中的现有用户数据

按多列对数据库中的现有用户进行排序

PassportJs Google Auth 将现有用户保存为数据库中的新用户。我该如何解决?

显示所有用户存储在数据库中的项目

获取存储在 TinyDB 数据库中的所有用户名

如何将迁移应用于数据库?

R将向量的标签应用于数据库

将 qcut 应用于具有用户定义的百分位值的数据框列

如何将代码优先迁移应用于Azure中的数据库?

将正则表达式应用于R中的SQL数据库

将 REGEXP 模式应用于数据库中的字符串列

将 Django 模型中的 default_value 应用于数据库

反应-验证数据库中是否有用户

使用MVC5中的现有用户数据库进行复杂身份验证

如何使用php在ejabberd数据库中添加现有用户的VCard详细信息

将Hibernate用于现有数据库

将现有数据库用于SSRS

将PCA应用于列表中存储的数据

重做日志是否存储所有应用于数据库缓冲区高速缓存的更改?

将显示设置应用于所有用户帐户?

如何将 dconf 和 gnome-shell 设置应用于所有用户

使用单独的现有用户数据库进行 Django 登录

如何将utf8_encode()或类似的值应用于数据库中的所有VARCHAR?(PHP / MySQL)

数据库将所有以前的迁移应用于更新,而不仅仅是新迁移

将OFFSET和FETCH NEXT应用于现有的存储过程

如何使用 CloudFormation 模板将 BucketPolicy (LifecycleConfiguration) 应用于现有存储桶?

是否将业务规则应用于C#代码或保存在数据库中?

有没有办法将原始输入存储在应用于python中数据框的函数中?