Spring OAuth2密码流一直失败

Posted

技术标签:

【中文标题】Spring OAuth2密码流一直失败【英文标题】:Spring OAuth2 Password Flow keeps failing 【发布时间】:2018-09-20 16:06:39 【问题描述】:

我正在尝试在我的 Spring Boot 应用程序中启用 OAuth2 密码流,但是,无论我尝试什么,我都无法让它运行。

以下是我的配置。 对于TokenStore,我配置了一个JdbcTokenStore bean,UserDetailsService 只是从我的自定义用户表中加载用户。 我还添加了属性security.oauth2.resource.filter-order=3

对于 Spring Boot,我使用的是 2.0.0.RELEASE,对于 Spring Security,我使用的是 2.3.0.RELEASE

授权服务器和资源服务器都在一个应用程序中。

以下 POST(使用 SoapUI)一直失败:

http://localhost:8080/oauth/token?grant_type=password&username=hans.wurst&password=bla&client_id=androidAppClient

我收到消息

访问被拒绝(用户是匿名的);

调试告诉我应用了以下过滤器:

Security filter chain: [
  WebAsyncManagerIntegrationFilter
  SecurityContextPersistenceFilter
  HeaderWriterFilter
  LogoutFilter
  BasicAuthenticationFilter
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  FilterSecurityInterceptor
]

授权服务器:

@Configuration
@EnableAuthorizationServer
class AuthorizationServerConfiguration : AuthorizationServerConfigurerAdapter() 

    @Autowired
    private lateinit var dataSource: DataSource

    @Autowired
    private lateinit var tokenStore: TokenStore

    @Autowired
    @Qualifier("authenticationManagerBean")
    private lateinit var authenticationManager: AuthenticationManager

    override fun configure(clients: ClientDetailsServiceConfigurer) 
        clients.jdbc(dataSource)
    

    override fun configure(endpoints: AuthorizationServerEndpointsConfigurer) 
        endpoints
                .authenticationManager(authenticationManager)
                .tokenStore(tokenStore)
    


网络安全:

@Configuration
class WebSecurityConfiguration : WebSecurityConfigurerAdapter() 

    @Autowired
    @Qualifier(USER_DETAILS_SERVICE)
    private lateinit var userDetailsService: UserDetailsService

    @Bean
    @Throws(Exception::class)
    override fun authenticationManagerBean(): AuthenticationManager = super.authenticationManagerBean()

    @Throws(Exception::class)
    override fun configure(web: WebSecurity) 
        web.debug(true)
    

    override fun configure(auth: AuthenticationManagerBuilder) 
        auth.userDetailsService(userDetailsService)
    

    override fun configure(http: HttpSecurity) 
        http
                .authorizeRequests()
                .anyRequest()
                .authenticated()
    

资源服务器:

@Configuration
@EnableResourceServer
class ResourceServerConfiguration : ResourceServerConfigurerAdapter() 

    override fun configure(http: HttpSecurity) 
        http
                .authorizeRequests()
                .antMatchers("/registration", "/customer/check")
                .anonymous()
                .anyRequest()
                .authenticated()
    


用户详情服务:

const val USER_DETAILS_SERVICE = "userDetailsService";

@Transactional
@Service(USER_DETAILS_SERVICE)
class CustomerUserDetailsService @Autowired constructor(private val customerRepository: CustomerRepository) : UserDetailsService 

    @Throws(UsernameNotFoundException::class)
    override fun loadUserByUsername(username: String): UserDetails =
            customerRepository
                    .findCustomerCredentialsByUserName(username)
                    ?.let  User(it.userName, it.password, emptyList()) 
                    ?: throw UsernameNotFoundException("Could not find customer with username $username")

【问题讨论】:

您可以尝试在 ResourceServerConfiguration 中添加“/registration”、“/customer/check”之外的“/oauth/token”、“/oauth/authorize”、“/oauth/confirm_access”吗? 【参考方案1】:

客户端androidAppClient 似乎没有在authorized_grant_types 中设置password 授权类型。

检查 DB (oauth_client_details) 中的客户端详细信息表,确保为此客户端设置了 password 授权类型。 如果它与其他授权类型一起设置,请确保授权类型中没有空格,例如 ('password,refresh_token').

/oauth/token 端点的 post 请求需要 Base64“clientId:clientSecret”格式的客户端凭据。

curl --request POST \
  --url http://localhost:8443/auth-service/oauth/token \
  --header 'authorization: Basic UkVXQVJEU19QT1QUxfQURNSU46cGFzc3dvcmQ=' \
  --header 'content-type: multipart/form-data; boundary=---011000010111000001101001' \
  --form username=testuser \
  --form password=password \
  --form grant_type=password

【讨论】:

oauth_client_details 中的客户端很好。对 client_id:client_secret 使用基本身份验证有效,并且我的请求已通过身份验证。但是,在那之后我收到了 404 响应,即使在日志中我可以看到 /oauth/token 已映射到 TokenEndpoint.postAccessToken 哦,好吧,我想通了。我在 Spring 中使用 JAX-RS 资源。这会以某种方式干扰 OAuth2 端点

以上是关于Spring OAuth2密码流一直失败的主要内容,如果未能解决你的问题,请参考以下文章

针对授权标头的Spring Security OAuth2 CORS问题

Google OAuth2.0 是不是支持资源所有者密码凭据流的 OAuth 流?

在 Spring Cloud Gateway 的 oauth2 客户端流中禁用重定向到 oauth2/authorization/registrationId

让 oauth2 与 spring-boot 和 rest 一起工作

oauth2 spring-security 成功和失败处理程序

使用 Spring Oauth2 实现 SAML 断言流