【问题标题】:Spring Oauth2 - reload principalsSpring Oauth2 - 重新加载主体
【发布时间】:2016-02-21 14:25:36
【问题描述】:

我已经使用 spring 安全模块实现了 OAuth2 密码授予。我添加了自己的 UserDetails 和 UserDetailsS​​ervice (jdbc) 实现。我将 User 注入到我的控制器中:

@AuthenticationPrincipal User user

其中 User 是我的 UserDetails 实现。 现在我想在不刷新令牌的情况下添加更改用户数据的可能性。

我尝试通过以下方式刷新主体:

User updatedUser = ...
Authentication newAuth = new UsernamePasswordAuthenticationToken(updatedUser, updatedUser.getPassword(), updatedUser.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(newAuth);

但它不起作用,当我调用另一个控制器方法时,它返回旧的用户对象。

有没有办法在不刷新令牌的情况下更改用户数据?是否有任何解决方案可以让 Spring Security 始终从数据库(而不是缓存)加载用户数据?

【问题讨论】:

  • 在应用程序的哪一层刷新principals?

标签: spring-security spring-oauth2


【解决方案1】:

我从this answer 找到了实现此目的的方法。我创建了HttpSessionSecurityContextRepository

@Bean
public ReloadUserPerRequestHttpSessionSecurityContextRepository userDetailContextRepository() {
    return new ReloadUserPerRequestHttpSessionSecurityContextRepository();
}

并将其从WebSecurityConfigurerAdapter 的类中添加到我的HttpSecurity

    .and()
        .csrf()
            .csrfTokenRepository(csrfTokenRepository())
    .and()
        .securityContext()
            .securityContextRepository(userDetailContextRepository())

以下是在每次请求时获取更新的用户信息的示例代码。您可以从您的 API 服务器或 oauth2 配置的 user-info-url 获取。

public class ReloadUserPerRequestHttpSessionSecurityContextRepository extends HttpSessionSecurityContextRepository {

    @Override
    public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
        SecurityContext context = super.loadContext(requestResponseHolder);

        Authentication auth = context.getAuthentication();
        if (auth != null && auth instanceof OAuth2Authentication) {
            OAuth2Authentication oldAuth = (OAuth2Authentication) auth;
            if (oldAuth.getPrincipal() instanceof LinkedHashMap) {
                createNewUserDetailsFromPrincipal(oldAuth.getPrincipal());
            }
            context.setAuthentication(oldAuth);
        }
        return context;
    }

    @SuppressWarnings("unchecked")
    private void createNewUserDetailsFromPrincipal(Object principal) {
        LinkedHashMap<String, Object> userDetailInfo = (LinkedHashMap<String, Object>) principal;
        // fetch User informations from your API server or your database or
        // 'user-info-url' of oauth2 endpoint
        userDetailInfo.put("name", "EDITED_USER_NAME");
    }

}

【讨论】:

    【解决方案2】:

    我不确定,但这只是一个猜测,我认为您还需要清除 SecurityContext

    首先使用SecurityContextHolder.clearContext(); 清除安全上下文,然后使用您的代码设置身份验证

    Authentication newAuth = new UsernamePasswordAuthenticationToken(updatedUser, updatedUser.getPassword(), updatedUser.getAuthorities());
    SecurityContextHolder.getContext().setAuthentication(newAuth);
    

    【讨论】:

    • 受 Oauth2 保护的应用程序无法使用 UsernamePasswordAuthenticationToken 类型身份验证进行分配。
    猜你喜欢
    • 2014-04-14
    • 2015-05-10
    • 2013-04-17
    • 2019-02-19
    • 2019-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多