简体   繁体   English

Java Spring Security OAuth2:通过POST接受客户端凭据

[英]Java Spring Security OAuth2: Accept client credentials via POST

I have a fairly basic Spring Boot setup and I have installed Spring Security and I have managed to successfully set up OAuth2 to protect my API. 我有一个相当基本的Spring Boot设置,我已经安装了Spring Security,并且我已成功设置OAuth2来保护我的API。

I had some trouble a few days back and asked (and answered) a question with regards to hitting my /oauth/token end point. 几天前我遇到了一些问题并询问(并回答了)关于击中我的/oauth/token终点的问题。 I soon figured out that the problem was that I was trying to send my client credentials in the body of my POST request but the token end point is configured in Spring Security to accept the client credentials ( client_id and secret ) via HTTP Basic Auth instead. 我很快就发现问题在于我试图在POST请求的主体中发送我的客户端凭据,但是在Spring Security中配置了令牌端点,以通过HTTP Basic Auth接受客户端凭据( client_idsecret )。

Most of my experience with consuming OAuth2 APIs has involved sending client credentials in the body of the POST request and I was wondering if it was possible to configure Spring Security to function in the same way? 我使用OAuth2 API的大多数经验都涉及在POST请求的主体中发送客户端凭据,我想知道是否可以将Spring Security配置为以相同的方式运行?

I've tried a few different things with no success, like setting the following configuration option, but I feel like that might only be used when configuring an OAuth2 client: 我尝试了一些不同的事情,但没有成功,比如设置以下配置选项,但我觉得这可能只在配置OAuth2客户端时使用:

security.oauth2.client.clientAuthenticationScheme=form

This is my Authorization server configuration. 这是我的授权服务器配置。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.approval.UserApprovalHandler;
import org.springframework.security.oauth2.provider.token.TokenStore;

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private UserApprovalHandler userApprovalHandler;

    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("client_id")
                .secret("secret")
                .authorizedGrantTypes("password", "authorization_code", "refresh_token")
                .scopes("read", "write")
                .accessTokenValiditySeconds(600)
                .refreshTokenValiditySeconds(3600);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(this.tokenStore)
                .userApprovalHandler(this.userApprovalHandler)
                .authenticationManager(this.authenticationManager);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) {
        security.tokenKeyAccess("permitAll()")
                .checkTokenAccess("isAuthenticated()")
                .passwordEncoder(this.passwordEncoder);
    }
}

As pointed out by @chrylis in the comments, the trick is to use the allowFormAuthenticationForClients method on AuthorizationServerSecurityConfigurer when configuring the authorization server. 正如@chrylis在评论中指出的那样,诀窍是在配置授权服务器时在AuthorizationServerSecurityConfigurer上使用allowFormAuthenticationForClients方法。 In my case, I have this in my AuthorizationServerConfig class: 就我而言,我在AuthorizationServerConfig类中有这个:

@Override
public void configure(AuthorizationServerSecurityConfigurer security) {
    security.tokenKeyAccess("permitAll()")
            .checkTokenAccess("isAuthenticated()")
            .passwordEncoder(this.passwordEncoder)
            .allowFormAuthenticationForClients();
}

That will allow passing client credentials via standard parameters, such as in the body of the POST request (or in the query string), though Spring prefers using HTTP Basic Auth by joining the client_id and secret together with a colon ( <client_id>:<secret> ), base-64 encoding the result, prefixing it with Basic and passing that to the Authorization header, so you would end up with something like this: 这将允许通过标准参数传递客户端凭据,例如在POST请求的主体(或查询字符串)中,尽管Spring更喜欢使用HTTP Basic Auth,通过将冒号( <client_id>:<secret>加入client_idsecret <client_id>:<secret> ),base-64编码结果,在Basic前面添加Basic并将其传递给Authorization标头,这样你就会得到类似这样的结果:

Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM