【问题标题】:How to use SecurityContext in CDI Async Events如何在 CDI 异步事件中使用 SecurityContext
【发布时间】:2023-02-10 03:49:45
【问题描述】:

我们已经将一些处理逻辑转移到 CDI 异步观察者,但是观察者中的一些业务方法有一些使用 securityContext.isCallerInRole(...) 来检查特定角色的安全检查。

由于 securityContext 不与异步线程一起传播,我们如何才能在观察者中实施应用程序安全性?我们的自定义 HttpAuthenticationMechanism 仅适用于 Servlet 生命周期,因此无法使用此机制触发身份验证。

我看不到任何以编程方式分配角色/组的方法,@RunAs 注释似乎只适用于 EJB 而不是 CDI bean

【问题讨论】:

    标签: jakarta-ee cdi jakarta-ee-security-api


    【解决方案1】:

    尚未在任何应用程序服务器中对此进行检查,但根据 CDI 2.0 规范,容器应为异步观察者提供相同的安全上下文:

    24.1.2。 Java EE 中的观察者方法调用上下文

    在 Java EE 中运行时,容器必须扩展定义的规则 在 Observer 方法调用上下文中,还必须确保所有 各种类型的观察者在相同的客户端安全上下文中被调用 调用 Event.fire() 或 Event.fireAsync() 或 BeanManager.fireEvent()。

    【讨论】:

      【解决方案2】:

      这是解决方案:

      • 创建 CustomPrincipal 来存储角色
      • 创建用于验证凭证并返回 CustomPrincipal 的 IdentityStore
      • 创建 ThreadLocal RolesHolder 来存储角色
      • 为每个请求生命周期管理 RolesHolder
      • 在其他线程中使用 RolesHolder

      创建 CustomPrincipal 来存储角色:

      public class CustomPrincipal extends CallerPrincipal {
          final Set<String> roles;
      
          public CustomPrincipal(String name, Set<String> roles) {
          this.roles = Collections.unmodifiableSet(new HashSet<>(roles));
          }
      
          public Set<String> getRoles() {
          return roles;
          }
      }
      

      创建您的 IdentityStore 以验证凭据并返回 CustomPrincipal

      @ApplicationScoped
      public class YourIdentityStore implements IdentityStore {
      
          @Override
              public CredentialValidationResult validate(Credential credential) {
              
              // TODO: Your verification of credential
          
              // Assume verification successful
              // You have roles/groups
              
              Set<String> roles = computed_roles
              
              return new CredentialValidationResult(
                     new CustomPrincipal(userNameFromCredential, roles), roles);
              }
      }
      

      使用 ThreadLocal 存储角色

      public class RolesHolder {
      
          // Must be InheritableThreadLocal, NOT new ThreadLocal<>()
          final ThreadLocal<Set<String>> holder = new InheritableThreadLocal<>();
      
          public static Set<String> get() {
          return this.holder.get();
          }
      
          public static void set(Set<String> value) {
          if (value == null) {
              this.holder.remove();
          } else {
              this.holder.set(value);
          }
          }
      }
      

      为每个请求生命周期管理 RolesHolder

      @WebFilter(urlPatterns = "your_mappings")
          public class RolesFilter extends HttpFilter {
              private static final long serialVersionUID = 1L;
          
              @Override
              protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
          
              try {
                  if (request.getUserPrincipal() != null) {
                  
                  CustomPrincipal customPrincipal = (CustomPrincipal)request.getUserPrincipal();
                  
                  // Store Roles in thread local
                  RolesHolder.set(customPrincipal.getRoles());
                  }
                  
                  chain.doFilter(request, response);
                  
              } finally {
                  
                  RolesHolder.set(null);
              }
              }
          }
      

      在其他线程中使用 RolesHolder

      if(RolesHolder.get()!=null&&RolesHolder.get().contains("CheckingRole")){
      
      // Do authorized roles things
      }
      

      【讨论】:

        猜你喜欢
        • 2017-08-29
        • 1970-01-01
        • 2018-12-26
        • 2013-06-24
        • 2016-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多