如何在Spring OAuth2Login OIDC中基于用户信息限制登录访问?
问题描述
已基于Spring Security配置OpenID Connect认证,过滤器链配置如下:
@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeRequests(authorizeRequests -> authorizeRequests .anyRequest().authenticated()) .oauth2Login(oauthLogin -> oauthLogin.permitAll()); return http.build(); }
当前所有OIDC用户均可登录,希望实现仅允许特定用户(如用户名是admin)通过认证的逻辑,曾尝试自定义AuthenticationProvider但出现principal为null的异常。
解决方案
不需要自定义AuthenticationProvider,Spring Security OIDC提供了更适配的方式实现用户准入控制,推荐两种方案:
方案一:自定义OidcUserService校验用户
在用户信息从OIDC提供商返回后,通过自定义OidcUserService进行校验,不符合条件则抛出认证异常,直接阻止登录:
@Bean public OidcUserService oidcUserService() { return new OidcUserService() { @Override public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException { OidcUser oidcUser = super.loadUser(userRequest); // 注意使用equals而非==比较字符串 if (!"admin".equals(oidcUser.getName())) { throw new OAuth2AuthenticationException( new OAuth2Error("invalid_user", "仅允许admin用户登录", null) ); } return oidcUser; } }; }
接着在过滤器链中配置使用该自定义服务:
@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeRequests(authorizeRequests -> authorizeRequests .anyRequest().authenticated()) .oauth2Login(oauthLogin -> oauthLogin .userInfoEndpoint(userInfo -> userInfo.oidcUserService(oidcUserService()))); return http.build(); }
方案二:通过授权规则限制资源访问
如果允许用户登录但限制其访问受保护资源,可直接在过滤器链中添加基于用户名的授权判断:
@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeRequests(authorizeRequests -> authorizeRequests .anyRequest().access((auth, context) -> new AuthorizationDecision("admin".equals(auth.getName())))) .oauth2Login(oauthLogin -> oauthLogin.permitAll()); return http.build(); }
关于自定义AuthenticationProvider的问题
OIDC认证流程中,AuthenticationProvider的执行时机早于用户信息加载步骤,此时principal尚未被初始化,因此会出现null异常。正确的校验时机是在用户信息获取完成后,也就是使用方案一中的OidcUserService。
内容的提问来源于stack exchange,提问作者Aleksandra Romanova
相关产品推荐
相关产品推荐

