12

我有一个 iOS 应用程序和一个用 Spring 编写的后端,实现了 OAuth2 mechanizm。

我的后端有一个signup端点,它接受一些用户数据并返回一个 OAuth2 响应,例如

{
    "access_token":"9154140d-b621-4391-9fdd-fbba9e5e4188",
    "token_type":"bearer",
    "refresh_token":"dd612036-7cc6-4858-a30f-c548fc2a823c",
    "expires_in":89,
    "scope":"write"
}

之后我想保存OIDAuthState在我的钥匙串中,所以我执行以下操作:

func saveTokenResponse(responseDict: [String: NSCopying & NSObjectProtocol]) {
        let redirectURI = URL(string: kRedirectURI)
        let configuration = OIDServiceConfiguration(authorizationEndpoint: URL(string: kAuthorizationEndpoint)!, tokenEndpoint: URL(string: kTokenEndpoint)!)
        let request = OIDAuthorizationRequest(configuration: configuration, clientId: self.kClientID, scopes: ["write"], redirectURL: redirectURI!, responseType: OIDResponseTypeCode, additionalParameters: nil)

        let accessToken = responseDict["access_token"] ?? nil
        let tokenType = responseDict["token_type"] ?? nil
        let refreshToken = responseDict["refresh_token"] ?? nil
        let expiresIn = responseDict["expires_in"] ?? nil
        let scope = responseDict["scope"] ?? nil

        let response = OIDAuthorizationResponse(request: request, parameters: [
            "access_token": accessToken!,
            "token_type": tokenType!,
            "refresh_token": refreshToken!,
            "expires_in": expiresIn!,
            "scope": scope!
            ]
        )
        let authState = OIDAuthState(authorizationResponse: response) //here authState.refreshToken is nil, so it won't be serialized.

        updateAuthState(authState: authState) // it just saves it in keychain
    }

一切正常,但是令牌过期时我遇到了问题。应用程序调用后端并且 AppAuth 无法刷新令牌:

OIDAuthState 没有刷新令牌

我可以看到,对象中不存在刷新令牌OIDAuthState。我检查了OIDAuthStatefrom的初始化,OIDAuthorizationResponse发现在这种情况下没有分配令牌。

任何人都可以帮助我OIDAuthState从后端收到的 OAuth 响应中保存吗?还是我做错了什么?

谢谢,

奥斯曼

4

4 回答 4

5

如果您的令牌过期,那么您将像所有应用程序(银行系统、亚马逊、Paytm 和 Facebook)一样进入登录屏幕(呼叫注销功能)。因此,用户在使用您的凭据登录时会获得与您想要的相同的响应并需要刷新令牌。您在登录 Web 服务中获得了类似的信息,如下面的响应。我希望它工作正常

    let accessToken = responseDict["access_token"] ?? nil
    let tokenType = responseDict["token_type"] ?? nil
    let refreshToken = responseDict["refresh_token"] ?? nil
    let expiresIn = responseDict["expires_in"] ?? nil
    let scope = responseDict["scope"] ?? nil

    let response = OIDAuthorizationResponse(request: request, parameters: [
        "access_token": accessToken!,
        "token_type": tokenType!,
        "refresh_token": refreshToken!,
        "expires_in": expiresIn!,
        "scope": scope!]
       )
于 2017-11-04T13:17:24.997 回答
2

我不知道你到底在做什么,但我建议你使用一种广泛使用的不同机制。

每次用户使用 Google 登录时,Google 都会发送一个临时访问令牌,该令牌会在短时间内过期。

  1. 您在登录时获得的访问令牌应发送到您的服务器,以查看并检查用户是否真实,并且也可以获取他的所有个人详细信息(通过 GoogleAPI 调用)。
  2. 用户通过 Google 登录后,立即将此访问令牌发送到您的服务器。在服务器端验证此令牌。
  3. 访问令牌通过身份验证后,将您自己的唯一令牌从您的服务器(是否有到期时间)发送给用户。
  4. 用户使用您提供的这个唯一令牌继续使用应用程序。
于 2017-11-21T13:21:20.350 回答
1

我使用 AppAuth for iOS 遇到了同样的问题(refreshToken 为空)。我可以通过在我的范围中添加“offline_access”来使其工作。

let request = OIDAuthorizationRequest(configuration: configuration!, clientId: self.kClientID, scopes: [OIDScopeOpenID, OIDScopeProfile, "api", "offline_access"], redirectURL: redirectURI! as URL, responseType: OIDResponseTypeCode, additionalParameters: nil)
于 2018-03-06T19:31:28.787 回答
0

将字符串更改let redirectURI = URL(string: kRedirectURI)为小写,ios 的 oAuth 很挑剔。也可以尝试将 Okta 用作直接插入 oAuth 的中间人服务。

于 2017-11-22T12:30:58.797 回答