简体   繁体   English

如何在spring security中更新用户权限后立即启用权限?

[英]How to immediately enable the authority after update user authority in spring security?

I'm using spring-security framework.When I update the permissions,It does not take effect immediately.I have to quit the current user(means logout), and then re-visit(means login) will be to update the user's permission.我使用的是spring-security框架,当我更新权限时,不会立即生效。我必须退出当前用户(意味着注销),然后重新访问(意味着登录)将更新用户的权限.

Is a way that immediately enable the authority after update user authority in spring security?是一种在spring security中更新用户权限后立即启用权限的方法吗?

You can set alwaysReauthenticate in your AbstractSecurityInterceptor like this您可以像这样在AbstractSecurityInterceptor 中设置 alwaysReauthenticate

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

Of course you should pay attention because 99,9% you don't need reauthentication.当然你应该注意,因为 99,9% 你不需要重新认证。 As authentication might use a database or something else your performance might degrade.由于身份验证可能会使用数据库或其他东西,您的性能可能会降低。 But usually you have a cache, like 2nd Level with hibernate, so loading the userdetails everytime should be an memory only operation in all cases where authorities havn't changed.但通常你有一个缓存,比如 2nd Level with hibernate,所以在所有权限没有改变的情况下,每次加载用户详细信息应该是一个仅限内存的操作。

Gandalf solution is valid but not complete.甘道夫解决方案有效但不完整。 In order for the new permissions to be considered by spring security (eg. allow access to pages previously not available), you need to create a new authentication object (eg. new UsernamePasswordAuthenticationToken) containing the new list of authorities.为了让 spring security 考虑新的权限(例如,允许访问以前不可用的页面),您需要创建一个包含新权限列表的新身份验证对象(例如,新的 UsernamePasswordAuthenticationToken)。

The following thread explains how to reload your user/principal every request:以下线程解释了如何重新加载您的用户/委托人每个请求:

Reload UserDetails Object from Database Every Request in Spring Security Spring Security 中的每个请求从数据库重新加载 UserDetails 对象


Full disclosure I am the author of the question and answer of the question in the above link.完全披露我是上述链接中问题的问答的作者。

Is not enough to reset the Thread Local context, you need to update the session too:不足以重置 Thread Local 上下文,您还需要更新会话:

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());

At least in google appengine the session is not a reference and by modifying the thread local doesn't get updated automatically, you have to manually session.set your object.至少在 google appengine 中,会话不是引用,并且通过修改本地线程不会自动更新,您必须手动 session.set 您的对象。

Since you didn't quite provide the exact details in your question, I assume that you have a situation where:由于您没有在问题中提供确切的细节,我假设您有以下情况:

  1. You are supplying a UserDetailsService to load up a UserDetails when a user attempts to login您正在提供 UserDetailsS​​ervice 以在用户尝试登录时加载 UserDetails
  2. As a part of that service, you are querying a database/DAO to load up details about a user's permissions, and are setting the granted authorities based on this作为该服务的一部分,您正在查询数据库/DAO 以加载有关用户权限的详细信息,并基于此设置授予的权限
  3. That when you say "When I update the permissions" you are referring to updating the user's permissions in the database (or whatever you are storing data in).当您说“当我更新权限时”时,您指的是更新用户在数据库中的权限(或您存储数据的任何内容)。

If so then what you are seeing is by design - Spring Security only loads the UserDetails for the user the first time, when they attempt to login, and then stores it in Session from then on.如果是这样,那么您所看到的就是设计 - Spring Security 仅在用户第一次尝试登录时加载 UserDetails,然后从那时起将其存储在 Session 中。 Generally this makes sense, as it avoids the application from having to perform the same queries about user details on each request.通常这是有道理的,因为它避免了应用程序必须对每个请求执行有关用户详细信息的相同查询。 Also, a user's permissions are generally not changing throughout 99.9% of their visits.此外,用户的权限在他们 99.9% 的访问中通常不会改变。

To change this behavior, you might want to look into adding a "refresh" command/page somewhere that will trigger some code (which you will have to write) which will re-query the UserDetailsService and replace the UserDetails in SecurityContext.要更改此行为,您可能需要考虑在某处添加一个“刷新”命令/页面,以触发一些代码(您必须编写),这些代码将重新查询 UserDetailsS​​ervice 并替换 SecurityContext 中的 UserDetails。 I don't believe there is any built-in way to do this.我不相信有任何内置的方法可以做到这一点。

You could create your own implementation of the UserDetails interface that is returned from your authentication mechanism, that allows access to the GrantedAuthorities[].您可以创建您自己的 UserDetails 接口的实现,该接口从您的身份验证机制返回,允许访问 GrantedAuthorities[]。 Then add your new authority directly to that UserDetails object.然后将您的新权限直接添加到该 UserDetails 对象。 You may run into issues if a user can have multiple sessions open at once (or if multiple users share the same generic login), that the new permissions will only be seen on the session you have altered.如果一个用户可以同时打开多个会话(或者如果多个用户共享同一个通用登录),您可能会遇到问题,即新权限只能在您更改的会话中看到。

你可以试试这个

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM