我想在我的spring-boot应用程序中设置 SwitchUserFilter ,该应用程序实现了spring-security-oauth2。我已经在 WebSecurityConfiguration 中设置了此扩展程序,该扩展程序扩展了 WebSecurityConfigurerAdapter 。
登录后,我获取了我的令牌,一个不记名令牌,我使用配置的端点来切换用户。
我在IDE中使用调试代码,显然 SecurityContextHolder 已更新,并注入了新的目标用户。
但是,当请求被重定向到目标URL(此过滤器的属性)时, SecurityContextHolder 会向我提供旧用户,而不是我所请求的。
我已经检查过 OAuth2AuthenticationProcessingFilter ,并且从请求中提取的令牌会返回相同的承载令牌,并通过它来构建用户详细信息并将其注入 SecurityContextHolder
有没有办法在oauth2方法中使用这种过滤器?
答案 0 :(得分:1)
问题是您需要创建一个包含新目标用户信息的新令牌。必须将此新令牌发送回客户端,因此对于将来的请求,将使用新的目标用户令牌。在我们的例子中,令牌持久存储在服务器端(使用JDBCTokenStore),但它也可以在完全服务器端的无状态环境(JWT-Token)中工作。
我们的环境是一个带有角度1.2客户端的spring-boot / jhipster应用程序。
创建新令牌:
@Inject
private UserDetailsService userDetailsService;
@Inject
private AuthorizationServerTokenServices tokenService;
@Inject
private ClientDetailsService clientDetailsService;
public OAuth2AccessToken createImpersonationAccessToken(String login) {
UserDetails userDetails = userDetailsService.loadUserByUsername(login);
log.info("Switching current user to {}", login);
Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
List<GrantedAuthority> impersonationAuthorities = new ArrayList<>(authorities);
Authentication source = SecurityContextHolder.getContext().getAuthentication();
// add current user authentication (to switch back from impersonation):
SwitchUserGrantedAuthority switchUserAuthority =
new SwitchUserGrantedAuthority(AuthoritiesConstants.IMPERSONATION, source);
impersonationAuthorities.add(switchUserAuthority);
UserDetails newUserDetails =
org.springframework.security.core.userdetails.User
.withUsername(login)
.authorities(impersonationAuthorities)
.password("justinventedhere")
.build();
Authentication userPasswordAuthentiation =
new UsernamePasswordAuthenticationToken(newUserDetails, null, impersonationAuthorities);
Map<String, String> parameters = new HashMap<>();
ClientDetails client = clientDetailsService.loadClientByClientId(clientId);
OAuth2Request oauthRequest = new OAuth2Request(parameters, client.getClientId(), client.getAuthorities(), true,
client.getScope(), client.getResourceIds(), null, null, null);
OAuth2Authentication authentication = new OAuth2Authentication(oauthRequest, userPasswordAuthentiation);
OAuth2AccessToken createAccessToken = tokenService.createAccessToken(authentication);
return createAccessToken;
}
这个新令牌返回给客户端(在我们的例子中是一个角度为1.2的应用程序),它将令牌存储在其本地存储中(用于下一个请求)。然后应用程序需要重新加载(更新目标用户的最简单方法):
vm.switchToClient = function (client) {
vm.switchingUser = true;
UserService.switchToClient(client, function(response) {
var expiredAt = new Date();
$localStorage.authenticationToken = response;
window.location.href='#/';
window.location.reload()
});
}
答案 1 :(得分:0)
您可以注入自己的AuthenticationManager并覆盖行为
private class AuthenticationManager extends OAuth2AuthenticationManager {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Authentication currentAuthentication = SecurityContextHolder.getContext().getAuthentication();
if (currentAuthentication instanceof UsernamePasswordAuthenticationToken) {
for (GrantedAuthority ga : currentAuthentication.getAuthorities()) {
if (ga instanceof SwitchUserGrantedAuthority) {
SwitchUserGrantedAuthority switchedFrom = (SwitchUserGrantedAuthority) ga;
Authentication switchedFromSource = switchedFrom.getSource();
for (GrantedAuthority sf : switchedFromSource.getAuthorities()) {
String authority = sf.getAuthority();
if (switchUserAuthority.equals(authority)) {
return currentAuthentication;
}
}
break;
}
}
}
return super.authenticate(authentication);
}