Spring Oauth2-重新加载主体



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

@AuthenticationPrincipal User user

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

我尝试用刷新主体

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

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

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

我从这个答案中找到了实现这一点的方法。我创建了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");
    }
}

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

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

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

最新更新