java - Spring Security 自定义身份验证提供程序总是导致错误的客户端凭据

标签 java spring authentication spring-security restful-authentication

我正在 spring security 中实现一个自定义身份验证提供程序来对用户进行身份验证。身份验证服务器位于远程端(Restful 服务)。每次我调用我的服务时都会遇到这个错误(这段代码到达

return new UsernamePasswordAuthenticationToken(userDetails, authentication.getCredentials().toString(), grantedAuthorities); 部分)

{"error":"invalid_client","error_description":"Bad client credentials"}

这是我的代码:

CustomAuthenticationProvider

public class CustomAuthenticationProvider implements AuthenticationProvider {


@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {

    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(HttpClients.createDefault());
    RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(60 * 1000)
            .setSocketTimeout(60 * 1000).build();
    PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
    poolingHttpClientConnectionManager.setMaxTotal(20);
    poolingHttpClientConnectionManager.setDefaultMaxPerRoute(20);
    CloseableHttpClient httpClientBuilder = HttpClientBuilder.create()
            .setConnectionManager(poolingHttpClientConnectionManager).setDefaultRequestConfig(requestConfig)
            .build();
    requestFactory.setHttpClient(httpClientBuilder);
    RestTemplate restTemplate = new RestTemplate(requestFactory);

    UserInfoRequestBean userInfoRequestBean = new UserInfoRequestBean();

    String username = (String)authentication.getPrincipal();
    userInfoRequestBean.setUsername(username);
    userInfoRequestBean.setPassword((String)authentication.getCredentials());

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);

    HttpEntity<?> httpEntity = new HttpEntity<UserInfoRequestBean>(userInfoRequestBean, headers);

    try{                                
        ResponseBean<LoginResponseBean> responseBody = restTemplate.exchange(getLoginUrl(), HttpMethod.POST, httpEntity, new ParameterizedTypeReference<ResponseBean<LoginResponseBean>>() {}).getBody();
        UserDetails userDetails = new UserDetails();
        userDetails.setGender(responseBody.getResult().getGender());
        userDetails.setLastLoginDate(new Date());
        userDetails.setYaghutSessionId(responseBody.getResult().getSessionId());
        userDetails.setName(responseBody.getResult().getName());
        userDetails.setUsername(username);

        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        // Granting authorization roles to user
        grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));

        return new UsernamePasswordAuthenticationToken(userDetails, authentication.getCredentials().toString(), grantedAuthorities);

    }catch (RestClientException exp) {
        exp.printStackTrace();
        //TODO: implement this method
    }

    return null;
}

@Override
public boolean supports(Class<?> authentication) {
    // TODO Auto-generated method stub
    return true;
}

private String getLoginUrl(){
    //return restful service url
}

}

Spring 安全配置

<bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />


<bean id="clientCredentialsTokenEndpointFilter"
      class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
    <property name="authenticationManager" ref="customAuthenticationManager" />
</bean>

<bean id="clientAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
    <property name="realmName" value="test/client" />
    <property name="typeName" value="Basic" />
</bean>


<bean id="customProvider"
    class="com.adpdigital.idm.security.provider.CustomAuthenticationProvider" />

<authentication-manager id="customAuthenticationManager"
    xmlns="http://www.springframework.org/schema/security">
    <authentication-provider ref="customProvider" />
</authentication-manager> 

<http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="customAuthenticationManager"
    xmlns="http://www.springframework.org/schema/security">
    <intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY"/>
    <anonymous enabled="false"/>
    <http-basic entry-point-ref="clientAuthenticationEntryPoint" />
    <!-- include this only if you need to authenticate clients via request parameters -->
    <custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER" />
    <access-denied-handler ref="oauthAccessDeniedHandler" />
</http>

最佳答案

在返回 UsernamePasswordAuthenticationToken 时,不传递 UserDetails 而是传递用户名。以下是示例 -

return new UsernamePasswordAuthenticationToken(username, authentication.getCredentials().toString(), grantedAuthorities);

关于java - Spring Security 自定义身份验证提供程序总是导致错误的客户端凭据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38565407/

相关文章:

java - SpringFox Swagger 与 Springboot 应用程序集成

java - 是否有工具可以可视化实时 Spring 应用程序上下文?

Java EE、Tomcat 和 SpringMVC

php - PHP 证书。两种方式的身份验证 ssl。 Apache

java - 无法读取java中文本文件的所有行

java - 在 1 GHz 处理器上运行 10-100 千万亿步的算法需要多长时间?

java - StringTokenizer 和 java.util.Scanner 类有什么区别

java - 我可以在不进行身份验证的情况下访问 SoundCloud API 吗?

authentication - 刷新或双击链接太快会导致 CakePHP 应用程序使用 Auth 组件将用户注销

java - 跟踪更改的数据库设计 - w/Hibernate