Spring Security 如何在Spring Authorization Server中使用自定义AuthenticationProvider传递用户进行身份验证的clientId?

kmb7vmvb  于 2023-05-22  发布在  Spring
关注(0)|答案(1)|浏览(259)

我正在使用Spring Authorization Server并在用户登录时实现自定义AuthenticationProvider,如下所示:

@Component
public class AuthenticationCallout implements AuthenticationProvider {
    private static final Logger LOG = LoggerFactory.getLogger(AuthenticationCallout.class);

    @Autowired
    private JpaOAuth2AuthorizationService jpaOAuth2AuthorizationService;

    private WebClient.Builder webClientBuilder;

    public AuthenticationCallout(WebClient.Builder webClientBuilder) {
        this.webClientBuilder = webClientBuilder;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        LOG.info("authenticate with username and password");

        final String name = authentication.getName();
        final String password = authentication.getCredentials().toString();

        LOG.info("authorities: {}, details: {}, credentials: {}", authentication.getAuthorities(),
                authentication.getDetails(), authentication.getCredentials());

        if (name.equals("admin") && password.equals("system")) {
            final List<GrantedAuthority> grantedAuths = new ArrayList<>();
            grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
            final UserDetails principal = new User(name, password, grantedAuths);
            LOG.info("returning using custom authenticator");
            final Authentication auth = new UsernamePasswordAuthenticationToken(principal, password, grantedAuths);
            return auth;
        } else {
            return null;
        }
    }

我还想获取此用户登录时使用的clientId。获取clientId的最佳方法是什么?在这个自定义身份验证中,我将对另一个服务进行webclient调用,该服务将用户密码与系统的clientId存储在一起。

kq0g1dla

kq0g1dla1#

有很多方法可以解决这个问题。例如,将您自己的Filter添加到Spring Security过滤器链中,您可以直接访问HttpServletRequestHttpServletResponse。但是,您也可以通过Spring的RequestContextHolder在非过滤器组件中访问它。
最简单的开始方式是实现UserDetailsService,并通过RequestCache访问用于启动流的SavedRequest,如下所示:

@Configuration
public class SecurityConfig {

    // ...

    @Bean
    public RequestCache requestCache() {
        return new HttpSessionRequestCache();
    }

    @Bean
    public UserDetailsService userDetailsService(RequestCache requestCache) {
        return (username) -> {
            var clientId = getClientId(requestCache);
            // ...
        };
    }

    private static String getClientId(RequestCache requestCache) {
        var requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        var request = requestAttributes.getRequest();
        var response = requestAttributes.getResponse();
        var savedRequest = requestCache.getRequest(request, response);
        return getParameter(savedRequest, OAuth2ParameterNames.CLIENT_ID);
    }

    private static String getParameter(SavedRequest savedRequest, String parameterName) {
        var parameterValues = savedRequest.getParameterValues(parameterName);
        if (parameterValues.length != 1) {
            throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_REQUEST);
        }
        return parameterValues[0];
    }

}

UserDetailsService可以从外部服务查找用户。这需要哈希密码作为微服务响应的一部分,因此DaoAuthenticationProvider可以在本地验证密码。

相关问题