Grails oAuth2 Provider 插件不对 grant_type 'password' 进行身份验证

Posted

技术标签:

【中文标题】Grails oAuth2 Provider 插件不对 grant_type \'password\' 进行身份验证【英文标题】:Grails oAuth2 Provider plugin does not authenticate for grant_type 'password'Grails oAuth2 Provider 插件不对 grant_type 'password' 进行身份验证 【发布时间】:2015-04-10 18:48:00 【问题描述】:

我有一个 ios 应用程序,它与在 Grails 上开发的 REST API 进行通信。为了保护 REST API,我决定使用 oAuth 2.0 'Resource Owner Password' 流程。为了让 grails 应用程序充当 oAuth 2.0 提供者,我使用以下 http://grails.org/plugin/spring-security-oauth2-provider 对于id为'client',secret为'1234',用户名为'user',密码为'password'的Client,获取token的请求如下

POST /oauth2-test/oauth/token HTTP/1.1
Host: 192.168.1.113:8080
Authorization: Basic Y2xpZW50OjEyMzQ=
Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded

grant_type=password&scope=read&username=user&password=password

收到的响应是


    "error": "unauthorized",
    "error_description": "Full authentication is required to access this  resource"

我对 Spring Security 和 oAuth 2.0 提供程序插件的 config.groovy 编辑如下所示

// Added by the Spring Security Core plugin:
grails.plugin.springsecurity.userLookup.userDomainClassName = 'test.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'test.UserRole'
grails.plugin.springsecurity.authority.className = 'test.Role'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
    '/':                              ['permitAll'],
    '/index':                         ['permitAll'],
    '/index.gsp':                     ['permitAll'],
    '/assets/**':                     ['permitAll'],
    '/**/js/**':                      ['permitAll'],
    '/**/css/**':                     ['permitAll'],
    '/**/images/**':                  ['permitAll'],
    '/**/favicon.ico':                ['permitAll'],
    '/oauth/authorize.dispatch': ["isFullyAuthenticated() and (request.getMethod().equals('GET') or request.getMethod().equals('POST'))"],
    '/oauth/token.dispatch'    : ["isFullyAuthenticated() and request.getMethod().equals('POST')"]
]

// Added by the Spring Security OAuth2 Provider plugin:
grails.plugin.springsecurity.oauthProvider.clientLookup.className = 'test.Client'
grails.plugin.springsecurity.oauthProvider.authorizationCodeLookup.className = 'test.AuthorizationCode'
grails.plugin.springsecurity.oauthProvider.accessTokenLookup.className = 'test.AccessToken'
grails.plugin.springsecurity.oauthProvider.refreshTokenLookup.className = 'test.RefreshToken'

grails.plugin.springsecurity.providerNames = [
        'clientCredentialsAuthenticationProvider',
        'daoAuthenticationProvider',
        'anonymousAuthenticationProvider',
        'rememberMeAuthenticationProvider'
]
grails.exceptionresolver.params.exclude = ['password', 'client_secret']
grails.plugin.springsecurity.filterChain.chainMap = [
        '/oauth/token': 'JOINED_FILTERS,-oauth2ProviderFilter,-securityContextPersistenceFilter,-logoutFilter,-rememberMeAuthenticationFilter',
        '/api/**': 'JOINED_FILTERS,-securityContextPersistenceFilter,-logoutFilter,-rememberMeAuthenticationFilter',
        '/**': 'JOINED_FILTERS,-statelessSecurityContextPersistenceFilter,-oauth2ProviderFilter,-clientCredentialsTokenEndpointFilter'
]
我做错了什么?我了解 oAuth 2.0 主要用于 授权而不是身份验证。所以我必须明确添加 用于身份验证的过滤器?我从 Grails 开始,没有任何 在 Springs 上的经验以及如何操作的任何帮助表示赞赏? grant_type 'password' 是否需要客户端身份验证?授予 输入“密码”应该用户身份验证不够吗?即使它 需要对客户端进行身份验证,它将使用基本身份验证 根据我的理解。所以我需要明确添加一个基本的 身份验证过滤器?

【问题讨论】:

您是否在 Authorization 标头中传递了 client_id 和 client_secret?您是否尝试在请求中传递它们? 是的,我在 Authorization 标头中传递了 client_id 和 client_secret。是的,尝试将它们作为 x-www-form-urlencoded 在请求中传递并得到相同的结果.. 没有变化。 请问您是如何解决这个问题的? Github上有一篇关于Spring Security OAuth2 Provider插件如何正确支持HTTP Basic Authentication的讨论:github.com/bluesliverx/grails-spring-security-oauth2-provider/… 【参考方案1】:

在 Spring Security Core 中默认不启用基本身份验证,因此您不能将 client_idclient_secret 放在 Authorization 标头中;在这种情况下,只需将它们添加到请求参数中(如grant_type

以下 CURL 示例应该可以工作:

curl -v -X POST \
-d "grant_type=password" \
-d "client_id=client" \
-d "client_secret=1234" \
-d "scope=read" \
-d "username=user" \
-d "password=password" http://localhost:8080/oauth2-test/oauth/token

"access_token":"d3eb1c1c-9922-4cfc-87e3-7efca9a8a2f2","token_type":"bearer","refresh_token":"e790efc2-e708-4391-9a7b-e4d86dc70816","expires_in":42545,"scope":"read"

请注意,OAuth2 需要 HTTPS。如果您使用 -https 选项 (grails run-app -https) 运行 Grails,则命令如下:

curl -v --insecure -X POST \
-d "grant_type=password" \
-d "client_id=client" \
-d "client_secret=1234" \
-d "scope=read" \
-d "username=user" \
-d "password=password" https://localhost:8443/oauth2-test/oauth/token

当我省略请求参数client_id时,得到如下回复:

"error":"unauthorized","error_description":"Full authentication is required to access this resource"

更新

如果您希望能够对 client_id 使用 HTTP 基本身份验证,则仅在 Spring Security Core(在 Config.groovy 中)启用基本身份验证不是解决方案,因为 BasicAuthenticationFilter 未以适合 oauth2 的方式初始化。当凭据正确或省略时,一切都按预期工作,但当凭据提供但错误时,您将收到 html 响应。

项目的 Github 页面上目前存在一个问题,其中讨论了处理基本身份验证的正确方法:

https://github.com/bluesliverx/grails-spring-security-oauth2-provider/issues/65

【讨论】:

我对密码授予类型有不同的问题我成功获得了访问令牌,但是当我尝试使用此访问令牌访问任何资源时,我得到 Bearer error="Invalid token" 你能帮我解决这个问题吗请问?

以上是关于Grails oAuth2 Provider 插件不对 grant_type 'password' 进行身份验证的主要内容,如果未能解决你的问题,请参考以下文章

使用 Grails 实现 OAuth2 提供程序

如何在 grails 和现有 oauth2 提供程序中使用 Spring Security 实现基于表单的登录

Grails OAuth2 登录密码凭据授予返回 invalid_client

Grails JMS插件到WebLogic JMS服务器

Grails spring security oauth2 提供者对具有正确承载令牌的资源的请求重定向到登录

Grails RestBuilder 简单的 POST 示例