【问题标题】:How to immediately enable the authority after update user authority in spring security?spring security中更新用户权限后如何立即启用权限?
【发布时间】:2010-10-27 22:09:06
【问题描述】:

我用的是spring-security框架。当我更新权限时,它不会立即生效。我必须退出当前用户(表示注销),然后重新访问(表示登录)将更新用户的权限。

spring security中更新用户权限后立即启用权限的方法吗?

【问题讨论】:

标签: java spring-security


【解决方案1】:

您可以在您的 AbstractSecurityInterceptor这样的

<bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
        <property name="alwaysReauthenticate" value="true"/>
 ...
</bean>

当然你应该注意,因为 99.9% 你不需要重新认证。由于身份验证可能使用数据库或其他东西,您的性能可能会降低。但是通常你有一个缓存,比如带有休眠的 2nd Level,所以每次加载 userdetails 应该是一个只在权限没有改变的情况下的内存操作。

【讨论】:

  • 如果我想保护 bean 上的方法,是否需要对另一个过滤器进行相同的更改,或者这样就足够了?
  • 据我所知,此过滤器仅适用于网络请求。如果您使用的是 METHODSecurityInterceptor,您可以自己调用 reauthenticate。但是,如果每个方法调用之前都检查这个网络过滤器,因为每个方法调用都在某个 http 请求中,你应该没问题
  • 这是正确答案。我只想补充一点,需要通过 部分中的&lt;sec:custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR"/&gt; 或通过拦截器属性将此拦截器合并到安全配置中:&lt;property name="securityMetadataSource"&gt; &lt;sec:filter-security-metadata-source&gt; &lt;sec:intercept-url pattern="/**" access="isAuthenticated()"/&gt; &lt;/property&gt;
【解决方案2】:

Gandalf 解决方案有效但不完整。为了让 Spring Security 考虑新权限(例如,允许访问以前不可用的页面),您需要创建一个包含新权限列表的新身份验证对象(例如,新 UsernamePasswordAuthenticationToken)。

【讨论】:

    【解决方案3】:

    以下线程解释了如何在每个请求中重新加载您的用户/主体:

    Reload UserDetails Object from Database Every Request in Spring Security


    完全披露我是上述链接中问题的问答作者。

    【讨论】:

      【解决方案4】:

      重置线程本地上下文还不够,还需要更新会话:

      UserContext userContext = (UserContext) context.getAuthentication().getPrincipal();
      if (userContext != null && userContext.getUsername() != null) {
          //This is my function to refresh the user details
          UserDetailsBean userDetails = getUserDetailsBean(userContext.getUsername());
          Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
          if (authentication instanceof UsernamePasswordAuthenticationToken) {
              UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication;
              auth.setDetails(userDetails);
          }
          return userDetails;
      } else {
          throw new ServiceException("User not authenticated");
      }
      request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
      

      至少在 google appengine 中,会话不是引用,并且通过修改本地线程不会自动更新,您必须手动 session.set 您的对象。

      【讨论】:

        【解决方案5】:

        由于您没有在问题中提供确切的详细信息,我假设您有以下情况:

        1. 您正在提供 UserDetailsS​​ervice 以在用户尝试登录时加载 UserDetails
        2. 作为该服务的一部分,您正在查询数据库/DAO 以加载有关用户权限的详细信息,并根据此设置授予的权限
        3. 当您说“当我更新权限时”时,您指的是更新用户在数据库(或您存储数据的任何内容)中的权限。

        如果是这样,那么您所看到的是设计使然 - Spring Security 仅在用户第一次尝试登录时为用户加载 UserDetails,然后从那时起将其存储在 Session 中。通常这是有道理的,因为它避免了应用程序必须对每个请求执行有关用户详细信息的相同查询。此外,用户的权限在 99.9% 的访问中通常不会发生变化。

        要更改此行为,您可能需要考虑在某处添加“刷新”命令/页面,该命令/页面将触发一些代码(您必须编写),这些代码将重新查询 UserDetailsS​​ervice 并替换 SecurityContext 中的 UserDetails。我不相信有任何内置方法可以做到这一点。

        【讨论】:

        • 你的假设是正确的。我想知道有什么好的方法可以做到这一点而不必重新登录。也许我可以修改存储在当前会话中的用户权限。我正在尝试到..
        【解决方案6】:

        您可以创建自己的 UserDetails 接口实现,该接口从您的身份验证机制返回,允许访问 GrantedAuthorities[]。然后将您的新权限直接添加到该 UserDetails 对象。如果一个用户可以同时打开多个会话(或者如果多个用户共享相同的通用登录名),您可能会遇到问题,新权限只会在您更改的会话上看到。

        【讨论】:

          【解决方案7】:

          你可以试试这个

          SecurityContextHolder.getContext().setAuthentication(SecurityContextHolder.getContext().getAuthentication());
          

          【讨论】:

          • 我试过这段代码,但不幸的是它没有任何影响。
          猜你喜欢
          • 2023-03-30
          • 2012-04-12
          • 1970-01-01
          • 2016-08-11
          • 1970-01-01
          • 2013-07-07
          • 2019-07-18
          • 2017-01-25
          • 2015-07-01
          相关资源
          最近更新 更多