Swift Vapor unsupported_grant_type 无效的签名/OAuth 访问令牌
Swift Vapor unsupported_grant_type invalid signature / OAuth access token
我是 运行 Xcode 8.1 和 SWIFT 3.
我正在向 google 服务器发送请求以获取身份验证令牌,因此我可以调用 FireBaseDB API,但出现错误:unsupported_grant_type/Invalid grant_type .
在 developers.google.com it says that I have to encode in a URL the following: https://www.googleapis.com/oauth2/v4/token + grant_type + 断言上,并在 POST 请求的正文中传递编码的 URL 。我将它作为字符串传递。
我注意到从我的服务帐户下载的 JSON 文件中的私钥包含 /n , ----,== 等字符,我应该在发布密钥之前删除它们吗?
let dateNow = Date()
var expDate = String(Int(dateNow.timeIntervalSince1970 + (60 * 60)))
var iatDate = String(Int(dateNow.timeIntervalSince1970))
let headerJWT = ["alg":"HS256","typ":"JWT"]
let jwtClaimSet =
["iss":"firebase-adminsdk-c7i48@fir-10c2e.iam.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/firebase.database",
"aud":"https://www.googleapis.com/oauth2/v4/token",
"exp": expDate,
"iat": iatDate]
//create and sign JSON Web Token
let jwt = try JWT(headers: Node(node: headerJWT),
payload: Node(node: jwtClaimSet),
signer: HS256(key:"-----BEGIN PRIVATE KEY-----\nMIIEvAWvQ== \n-----END PRIVATE KEY-----\n"))
// Store JSON Web Token
let JWTtoken = try jwt.createToken()
func createUrlWithString() -> NSURL {
var urlString = "https://www.googleapis.com/oauth2/v4/token"
urlString.append("?grant_type=")
urlString.append("urn:ietf:params:oauth:grant-type:jwt-bearer")
urlString.append("&assertion=")
urlString.append(JWTtoken)
return NSURL(string: urlString)!
}
// make the body input for our POST
let bodyURL = createUrlWithString().absoluteURL
drop.get("any") { request in
let response =
try drop.client.request(.other(method:"Post"),
"https://www.googleapis.com/oauth2/v4/token",
headers: ["Content-Type": "application/x-www-form-urlencoded"],
query: [:],
body: String(describing: bodyURL) )
let serverResp = response.headers
let serverBody = response.body.bytes
let serverJson = try JSON(bytes: serverBody!)
print(serverJson)
return "POST Request went through"
}
更新
根据 Karol Gasienica 的建议,我将 grant_type
和 assertion
参数作为 POST 请求参数传递。现在我得到 "error_description": Node.Node.string("SSL is required to perform this operation.")]))
func createUrlWithString() -> NSURL {
var urlString = "https://www.googleapis.com/oauth2/v4/token"
urlString.append("?grant_type=")
urlString.append("urn:ietf:params:oauth:grant-type:jwt-bearer")
urlString.append("&assertion=")
urlString.append(JWTtoken)
return NSURL(string: urlString)!
}
let response = try drop.client.request(.other(method:"Post"),
String(describing: bodyURL),
headers: ["Content-Type": "application/x-www-form-urlencoded"],
query: [:])
您的代码似乎没有正确设置grant_type
:
urlString.append("?grant_type=")
你的情况可能是 grant_type=authorization_code
或者
grant_type=jwt-bearer
你好像把 grant_type
设置错了地方。
更新
另外我认为 grant_type 和断言参数不是作为请求 headers 传递的,而是作为 post 请求参数
更新
我不太确定您是否使用正确的方式放置 POST (body) 参数。在 this 文档中是如何使用 post 婴儿车创建请求的示例,如下所示:
try drop.client.request(.other(method: "POST"), "http://some-domain", headers: ["My": "Header"], query: ["key": "value"], body: [])
当您生成服务帐户凭据时,您需要牢记以下内容,摘自https://cloud.google.com/storage/docs/authentication
:
您可以通过为服务帐号创建 OAuth 客户端 ID,在 Cloud Platform Console 中创建私钥。您可以获得 JSON 和 PKCS12 格式的私钥:
如果您在 Google Cloud Platform 之外的生产环境中使用 Application Default Credentials,则需要 JSON 密钥。 JSON 密钥无法转换为其他格式。
许多不同的编程语言和库都支持 PKCS12 (.p12)。如果需要,您可以使用 OpenSSL (see Converting the private key to other formats) 将密钥转换为其他格式。但是,PKCS12 密钥无法转换为 JSON 格式。
- 创建您的服务帐户,然后下载您的 .p12 文件。
使用 OpenSSL
将 p.12 (a.k.a pkcs12) 文件转换为 .pem (a.k.a pkcs1)
cat /path/to/xxxx-privatekey.p12 | openssl pkcs12 -nodes -nocerts -passin pass:notasecret | openssl rsa > /path/to/secret.pem
转到github并搜索VaporJWT并将其导入Xcode。它将帮助您创建签名的 JSON Web 令牌。
在此 github 页面上,您将了解如何提取私钥以供 RSA 使用。
// 将 .pem 转换为 der
openssl rsa -in /path/to/secret.pem -outform der -out /path/to/private.der
//将.der转换为.base64
openssl base64 -in /path/to/private.der -out /path/to/Desktop/private.txt
在 private.txt 中,您拥有以 base64 编码的私钥,您最终可以使用它来签署 JWT。然后您可以使用已签名的 JWT 调用 Google API。
</code></p>
<pre><code>import Vapor
import VaporJWT
let drop = Droplet()
var tokenID:String!
//set current date
let dateNow = Date()
// assign to expDate the validity period of the token returnd by OAuth server (3600 seconds)
var expDate = String(Int(dateNow.timeIntervalSince1970 + (60 * 60)))
// assign to iatDate the time when the call was made to request an access token
var iatDate = String(Int(dateNow.timeIntervalSince1970))
// the header of the JSON Web Token (first part of the JWT)
let headerJWT = ["alg":"RS256","typ":"JWT"]
// the claim set of the JSON Web Token
let jwtClaimSet =
["iss":"firebase-adminsdk-c7i38@fir-30c9e.iam.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/firebase.database",
"aud":"https://www.googleapis.com/oauth2/v4/token",
"exp": expDate,
"iat": iatDate]
//Using VaporJWT construct a JSON Web Token and sign it with RS256 algorithm
//The only signing algorithm supported by the Google OAuth 2.0 Authorization Server is RSA using SHA-256 hashing algorithm.
let jwt = try JWT(headers: Node(node: headerJWT), payload: Node(node:jwtClaimSet), encoding: Base64URLEncoding(), signer: RS256(encodedKey: "copy paste here what you have in private.txt as explained at point 7 above "))
// create the JSON Web Token
let JWTtoken = try jwt.createToken()
let grant_type = "urn:ietf:params:oauth:grant-type:jwt-bearer" // this value must not be changed
let unreserved = "*-._"
let allowed = NSMutableCharacterSet.alphanumeric()
allowed.addCharacters(in: unreserved)
// percent or URL encode grant_type
let grant_URLEncoded = grant_type.addingPercentEncoding(withAllowedCharacters: allowed as CharacterSet)
// create a string made of grant_type and assertion. NOTE!!! only grant_type's value is URL encoded.
//JSON Web Token value does not need to be URL encoded
var fullString = "grant_type=\(grant_URLEncoded!)&assertion=\(JWTtoken)"
//pass fullString in the body parameter
drop.get("call") { request in
let response = try drop.client.post("https://www.googleapis.com/oauth2/v4/token", headers: ["Content-Type": "application/x-www-form-urlencoded"], query: [:],body: fullString)
let serverResp = response.headers
let serverBody = response.body.bytes
let serverJson = try JSON(bytes: serverBody!)
print(serverJson)
return "Success"
}
我是 运行 Xcode 8.1 和 SWIFT 3.
我正在向 google 服务器发送请求以获取身份验证令牌,因此我可以调用 FireBaseDB API,但出现错误:unsupported_grant_type/Invalid grant_type .
在 developers.google.com it says that I have to encode in a URL the following: https://www.googleapis.com/oauth2/v4/token + grant_type + 断言上,并在 POST 请求的正文中传递编码的 URL 。我将它作为字符串传递。
我注意到从我的服务帐户下载的 JSON 文件中的私钥包含 /n , ----,== 等字符,我应该在发布密钥之前删除它们吗?
let dateNow = Date()
var expDate = String(Int(dateNow.timeIntervalSince1970 + (60 * 60)))
var iatDate = String(Int(dateNow.timeIntervalSince1970))
let headerJWT = ["alg":"HS256","typ":"JWT"]
let jwtClaimSet =
["iss":"firebase-adminsdk-c7i48@fir-10c2e.iam.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/firebase.database",
"aud":"https://www.googleapis.com/oauth2/v4/token",
"exp": expDate,
"iat": iatDate]
//create and sign JSON Web Token
let jwt = try JWT(headers: Node(node: headerJWT),
payload: Node(node: jwtClaimSet),
signer: HS256(key:"-----BEGIN PRIVATE KEY-----\nMIIEvAWvQ== \n-----END PRIVATE KEY-----\n"))
// Store JSON Web Token
let JWTtoken = try jwt.createToken()
func createUrlWithString() -> NSURL {
var urlString = "https://www.googleapis.com/oauth2/v4/token"
urlString.append("?grant_type=")
urlString.append("urn:ietf:params:oauth:grant-type:jwt-bearer")
urlString.append("&assertion=")
urlString.append(JWTtoken)
return NSURL(string: urlString)!
}
// make the body input for our POST
let bodyURL = createUrlWithString().absoluteURL
drop.get("any") { request in
let response =
try drop.client.request(.other(method:"Post"),
"https://www.googleapis.com/oauth2/v4/token",
headers: ["Content-Type": "application/x-www-form-urlencoded"],
query: [:],
body: String(describing: bodyURL) )
let serverResp = response.headers
let serverBody = response.body.bytes
let serverJson = try JSON(bytes: serverBody!)
print(serverJson)
return "POST Request went through"
}
更新
根据 Karol Gasienica 的建议,我将 grant_type
和 assertion
参数作为 POST 请求参数传递。现在我得到 "error_description": Node.Node.string("SSL is required to perform this operation.")]))
func createUrlWithString() -> NSURL {
var urlString = "https://www.googleapis.com/oauth2/v4/token"
urlString.append("?grant_type=")
urlString.append("urn:ietf:params:oauth:grant-type:jwt-bearer")
urlString.append("&assertion=")
urlString.append(JWTtoken)
return NSURL(string: urlString)!
}
let response = try drop.client.request(.other(method:"Post"),
String(describing: bodyURL),
headers: ["Content-Type": "application/x-www-form-urlencoded"],
query: [:])
您的代码似乎没有正确设置grant_type
:
urlString.append("?grant_type=")
你的情况可能是 grant_type=authorization_code
或者
grant_type=jwt-bearer
你好像把 grant_type
设置错了地方。
更新
另外我认为 grant_type 和断言参数不是作为请求 headers 传递的,而是作为 post 请求参数
更新
我不太确定您是否使用正确的方式放置 POST (body) 参数。在 this 文档中是如何使用 post 婴儿车创建请求的示例,如下所示:
try drop.client.request(.other(method: "POST"), "http://some-domain", headers: ["My": "Header"], query: ["key": "value"], body: [])
当您生成服务帐户凭据时,您需要牢记以下内容,摘自https://cloud.google.com/storage/docs/authentication
:
您可以通过为服务帐号创建 OAuth 客户端 ID,在 Cloud Platform Console 中创建私钥。您可以获得 JSON 和 PKCS12 格式的私钥:
JSON 密钥。 JSON 密钥无法转换为其他格式。 许多不同的编程语言和库都支持 PKCS12 (.p12)。如果需要,您可以使用 OpenSSL (see Converting the private key to other formats) 将密钥转换为其他格式。但是,PKCS12 密钥无法转换为 JSON 格式。
- 创建您的服务帐户,然后下载您的 .p12 文件。
使用 OpenSSL
将 p.12 (a.k.a pkcs12) 文件转换为 .pem (a.k.a pkcs1)
cat /path/to/xxxx-privatekey.p12 | openssl pkcs12 -nodes -nocerts -passin pass:notasecret | openssl rsa > /path/to/secret.pem
转到github并搜索VaporJWT并将其导入Xcode。它将帮助您创建签名的 JSON Web 令牌。
在此 github 页面上,您将了解如何提取私钥以供 RSA 使用。
// 将 .pem 转换为 der
openssl rsa -in /path/to/secret.pem -outform der -out /path/to/private.der
//将.der转换为.base64
openssl base64 -in /path/to/private.der -out /path/to/Desktop/private.txt
在 private.txt 中,您拥有以 base64 编码的私钥,您最终可以使用它来签署 JWT。然后您可以使用已签名的 JWT 调用 Google API。
</code></p>
<pre><code>import Vapor
import VaporJWT
let drop = Droplet()
var tokenID:String!
//set current date
let dateNow = Date()
// assign to expDate the validity period of the token returnd by OAuth server (3600 seconds)
var expDate = String(Int(dateNow.timeIntervalSince1970 + (60 * 60)))
// assign to iatDate the time when the call was made to request an access token
var iatDate = String(Int(dateNow.timeIntervalSince1970))
// the header of the JSON Web Token (first part of the JWT)
let headerJWT = ["alg":"RS256","typ":"JWT"]
// the claim set of the JSON Web Token
let jwtClaimSet =
["iss":"firebase-adminsdk-c7i38@fir-30c9e.iam.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/firebase.database",
"aud":"https://www.googleapis.com/oauth2/v4/token",
"exp": expDate,
"iat": iatDate]
//Using VaporJWT construct a JSON Web Token and sign it with RS256 algorithm
//The only signing algorithm supported by the Google OAuth 2.0 Authorization Server is RSA using SHA-256 hashing algorithm.
let jwt = try JWT(headers: Node(node: headerJWT), payload: Node(node:jwtClaimSet), encoding: Base64URLEncoding(), signer: RS256(encodedKey: "copy paste here what you have in private.txt as explained at point 7 above "))
// create the JSON Web Token
let JWTtoken = try jwt.createToken()
let grant_type = "urn:ietf:params:oauth:grant-type:jwt-bearer" // this value must not be changed
let unreserved = "*-._"
let allowed = NSMutableCharacterSet.alphanumeric()
allowed.addCharacters(in: unreserved)
// percent or URL encode grant_type
let grant_URLEncoded = grant_type.addingPercentEncoding(withAllowedCharacters: allowed as CharacterSet)
// create a string made of grant_type and assertion. NOTE!!! only grant_type's value is URL encoded.
//JSON Web Token value does not need to be URL encoded
var fullString = "grant_type=\(grant_URLEncoded!)&assertion=\(JWTtoken)"
//pass fullString in the body parameter
drop.get("call") { request in
let response = try drop.client.post("https://www.googleapis.com/oauth2/v4/token", headers: ["Content-Type": "application/x-www-form-urlencoded"], query: [:],body: fullString)
let serverResp = response.headers
let serverBody = response.body.bytes
let serverJson = try JSON(bytes: serverBody!)
print(serverJson)
return "Success"
}