我的用例是这样的:在多租户应用中,每个租户都可以配置自己的SSO IDP身份验证机制。他们还可以配置在新用户通过身份验证后是否应在本地应用中自动创建新用户。
我正在使用Spring Security,并且有多个Oauth2提供程序正在工作。
当我在不允许自动创建新用户的租户上对新用户进行身份验证时,如何覆盖身份验证,以便Spring Security将此用户登录视为失败,因此将继续保护对其中所有资源的访问该应用程序?
同样,如果允许自动创建,我应该在哪里添加代码来创建新用户?
更新:
似乎基本是这样的-对于Spring Security 5,您需要实现自己的OAuth2UserService,要么(一个或两个)要么接受OAuth2UserRequest并返回OAuth2User,要么接受OidcUserRequest并返回OidcUser
这些可以配置为:
protected void configure(HttpSecurity http) throws Exception
{
http...
.userInfoEndpoint()
.userService(securityUserService)
.oidcUserService(commonOAuth2UserService)
...;
}
其中securityUserService是实现OAuth2UserService的@Component,而commonOAuth2UserService是实现OAuth2UserService的@Component。请注意,您可能只需要其中之一-我会同时使用,因为我有多种不同类型的IDP。
但是,这还不是一个完整的答案,因为我仍在努力解决一件事:我需要从idToken中获得一个可靠的值,该值告诉我需要查找的用户。我希望能够以原始请求的状态(通过实现我自己的OAuth2AuthorizationRequestResolver)将其作为状态传递,但是我发现在那里设置的状态不会显示在Okta或Azure AD的idToken中。
任何人都知道为什么状态值不能显示在另一边吗?
一种解决方法似乎是使用我得到的电子邮件地址,但是每个IDP都提供了不同的方式,并且它们都警告不要将这些属性用于任何重要的事情,因此,这似乎是一个非常脆弱的解决方案,可能现在可以使用,但不可行以后。
警告那些可能会遵循此规则的人:不要被谷歌搜索所发现的使用PrincipalExtractor和AuthoritiesExtractor的大量引用分散注意力-这是最新的Spring Security不再支持的旧技术。 em>
OAuth2UserService实现:
@Component
public class CommonOAuth2UserService
implements OAuth2UserService<OidcUserRequest, OidcUser>
{
final OidcUserService delegate = new OidcUserService();
@Override
public OidcUser loadUser(OidcUserRequest userRequest)
throws OAuth2AuthenticationException
{
// Delegate to the default implementation for loading a user
OidcUser oidcUser = delegate.loadUser(userRequest);
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
mappedAuthorities.add(new SecurityRole("ROLE_USER"));
oidcUser = new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo());
return oidcUser;
}
}
和OAuth2AuthorizationRequestResolver:
public class CustomAuthorizationRequestResolver
implements OAuth2AuthorizationRequestResolver
{
private OAuth2AuthorizationRequestResolver defaultResolver;
public CustomAuthorizationRequestResolver(
ClientRegistrationRepository repo
)
{
defaultResolver = new DefaultOAuth2AuthorizationRequestResolver(repo, "/oauth2/authorization");
}
@Override
public OAuth2AuthorizationRequest resolve(HttpServletRequest httpServletRequest)
{
OAuth2AuthorizationRequest request = defaultResolver.resolve(httpServletRequest);
if (request == null) return null;
OAuth2AuthorizationRequest returnreq = OAuth2AuthorizationRequest.from(request)
.state(request.getState() + ";euamid=kdc123")
.build();
return returnreq;
}
@Override
public OAuth2AuthorizationRequest resolve(HttpServletRequest httpServletRequest, String s)
{
OAuth2AuthorizationRequest request = defaultResolver.resolve(httpServletRequest, s);
if (request == null) return null;
return OAuth2AuthorizationRequest.from(request)
.state(request.getState()+";euamid=kdc123")
.build();
}
}