无法使用 Developer Authentication Swift Cognito 承担经过身份验证的角色
Can't assume authenticated role with Developer Authentication Swift Cognito
我可以从 LambdAuth(我的开发人员身份验证)成功检索到令牌和身份,但是当我尝试使用服务时,Cognito 承担了一个未经身份验证的角色。这是我的错误:
Error Domain=com.amazonaws.AWSDynamoDBErrorDomain Code=1 "(null)" UserInfo={Message=User: arn:aws:sts::xxxxxxxxxx:assumed-role/Cognito_LambdAuthUnauth_Role/CognitoIdentityCredentials is not authorized to perform: dynamodb:ListTables on resource: *, __type=com.amazon.coral.service#AccessDeniedException}
我期待的角色是 CognitoLambdAuthAuth_Role。
这是我的身份提供商代码:
// MyIdentityProvider.swift
import Foundation
import AWSCore
import AWSCognito
import AWSLambda
class MyIdentityProvider: AWSAbstractCognitoIdentityProvider {
var _token: String!
var _logins: [ NSObject : AnyObject ]!
var email: String!
var password: String!
override var token: String {
get {
return _token
}
}
override var logins: [ NSObject : AnyObject ]! {
get {
return _logins
}
set {
_logins = newValue
}
}
override func getIdentityId() -> AWSTask! {
if self.identityId != nil {
return AWSTask(result: self.identityId)
}else{
return AWSTask(result: nil).continueWithBlock({ (task) -> AnyObject! in
if self.identityId == nil {
return self.refresh()
}
return AWSTask(result: self.identityId)
})
}
}
override func refresh() -> AWSTask! {
let invocationRequest = AWSLambdaInvokerInvocationRequest()
invocationRequest.functionName = "LambdAuthLogin"
invocationRequest.invocationType = AWSLambdaInvocationType.RequestResponse
invocationRequest.payload = ["email" : "me@example.com", "password" : "password"]
//self.activeSearchRequest = invocationRequest
let lambdaInvoker = AWSLambdaInvoker.defaultLambdaInvoker()
let task = lambdaInvoker.invoke(invocationRequest).continueWithSuccessBlock() { (task) -> AWSTask! in
if (task.error != nil) {
// failed to retrieve token.
print("Error invoking lambda function: ", task.error)
} else {
//print("response: ", task.result)
if let payload = task.result.payload as? [String: AnyObject] {
if(payload["login"] as! Int == 1) {
// The following 3 lines are required as referenced here:
var tmp = NSMutableDictionary()
tmp.setObject(self.email, forKey: "cognito-identity.amazonaws.com")
self.logins = tmp as [NSObject : AnyObject]
self.identityId = payload["identityId"] as! String
self._token = payload["token"] as! String
}
print("id", payload["identityId"])
print("token: ", payload["token"])
print("logins map", self.logins)
}
}
return task
}
return task
}
}
这里是我调用生成错误的 DynamoDB 调用的地方:
let dynamoDB = AWSDynamoDB.defaultDynamoDB()
let listTableInput = AWSDynamoDBListTablesInput()
print("listing dynamoDB tables..")
let finalTask = dynamoDB.listTables(listTableInput).continueWithBlock{ (task: AWSTask!) -> AnyObject! in
if (task.error != nil) {
// failed to retrieve identityId.
if let handler = completionHandler {
print("Store Data Error occurred: \(task.error)")
handler(false)
}
return task
} else {
print("Store Data Succeeded...")
let listTablesOutput = task.result as! AWSDynamoDBListTablesOutput
for tableName : AnyObject in listTablesOutput.tableNames {
print("\(tableName)")
}
if let handler = completionHandler {
handler(true)
}
return task
}
}
以及在 DynamoDB 调用之前检索身份的代码:
func getAuthCognitoId(email: String, password: String, identityProvider: MyIdentityProvider)->AWSTask! {
identityProvider.email = email
identityProvider.password = password
// TODO: Store to a keychain
let task = identityProvider.getIdentityId().continueWithSuccessBlock() { (task) -> AWSTask! in
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: AWSRegionType.USEast1, identityProvider: identityProvider, unauthRoleArn: Constants.ARNUnauth.value, authRoleArn: Constants.ARNAuth.value)
let defaultServiceConfiguration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: credentialsProvider)
AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = defaultServiceConfiguration
return task
}
return task
}
编辑 2015 年 12 月 8 日:
我在我的lambda函数前添加了API网关,仍然无法获得授权角色。它成功检索到令牌和 idenityId,但是:
override func refresh() -> AWSTask! {
let task = AWSTaskCompletionSource()
let request = AFHTTPRequestOperationManager()
request.requestSerializer.setValue(email, forHTTPHeaderField: "email")
request.requestSerializer.setValue(password, forHTTPHeaderField: "password")
request.GET(Constants.loginUrl.value, parameters: nil, success: { (request: AFHTTPRequestOperation!, response: AnyObject!) -> Void in
print("request: ", request)
// The following 3 lines are required as referenced here:
self.logins = [self.developerProvider: self.email]
// Get the properties from my server response
print("response: ", response)
let identityId = response.objectForKey("identityId")as! String
let token = response.objectForKey("token")as! String
// Set the identityId and token for the ExampleAppIdentityProvider
self.identityId = identityId
self._token = token
task.setResult(self.identityId)
}, failure: { (request: AFHTTPRequestOperation?, error: NSError!) -> Void in
task.setError(error)
})
return task.task
}
问题是您使用未经授权的凭据调用 lambda
let lambdaInvoker = AWSLambdaInvoker.defaultLambdaInvoker()
由于它将这些凭据存储在钥匙串中以供后续请求使用,并且仅在它们过期时刷新它们,因此您在调用 DDB 时仍在使用未经授权的凭据。尝试使用 api-gateway 对您的 lambda 身份验证进行前置,这样您就不需要像您的评论中提到的那样使用 unauth 凭据开始,如果您仍然有问题,请告诉我。
我可以从 LambdAuth(我的开发人员身份验证)成功检索到令牌和身份,但是当我尝试使用服务时,Cognito 承担了一个未经身份验证的角色。这是我的错误:
Error Domain=com.amazonaws.AWSDynamoDBErrorDomain Code=1 "(null)" UserInfo={Message=User: arn:aws:sts::xxxxxxxxxx:assumed-role/Cognito_LambdAuthUnauth_Role/CognitoIdentityCredentials is not authorized to perform: dynamodb:ListTables on resource: *, __type=com.amazon.coral.service#AccessDeniedException}
我期待的角色是 CognitoLambdAuthAuth_Role。
这是我的身份提供商代码:
// MyIdentityProvider.swift
import Foundation
import AWSCore
import AWSCognito
import AWSLambda
class MyIdentityProvider: AWSAbstractCognitoIdentityProvider {
var _token: String!
var _logins: [ NSObject : AnyObject ]!
var email: String!
var password: String!
override var token: String {
get {
return _token
}
}
override var logins: [ NSObject : AnyObject ]! {
get {
return _logins
}
set {
_logins = newValue
}
}
override func getIdentityId() -> AWSTask! {
if self.identityId != nil {
return AWSTask(result: self.identityId)
}else{
return AWSTask(result: nil).continueWithBlock({ (task) -> AnyObject! in
if self.identityId == nil {
return self.refresh()
}
return AWSTask(result: self.identityId)
})
}
}
override func refresh() -> AWSTask! {
let invocationRequest = AWSLambdaInvokerInvocationRequest()
invocationRequest.functionName = "LambdAuthLogin"
invocationRequest.invocationType = AWSLambdaInvocationType.RequestResponse
invocationRequest.payload = ["email" : "me@example.com", "password" : "password"]
//self.activeSearchRequest = invocationRequest
let lambdaInvoker = AWSLambdaInvoker.defaultLambdaInvoker()
let task = lambdaInvoker.invoke(invocationRequest).continueWithSuccessBlock() { (task) -> AWSTask! in
if (task.error != nil) {
// failed to retrieve token.
print("Error invoking lambda function: ", task.error)
} else {
//print("response: ", task.result)
if let payload = task.result.payload as? [String: AnyObject] {
if(payload["login"] as! Int == 1) {
// The following 3 lines are required as referenced here:
var tmp = NSMutableDictionary()
tmp.setObject(self.email, forKey: "cognito-identity.amazonaws.com")
self.logins = tmp as [NSObject : AnyObject]
self.identityId = payload["identityId"] as! String
self._token = payload["token"] as! String
}
print("id", payload["identityId"])
print("token: ", payload["token"])
print("logins map", self.logins)
}
}
return task
}
return task
}
}
这里是我调用生成错误的 DynamoDB 调用的地方:
let dynamoDB = AWSDynamoDB.defaultDynamoDB()
let listTableInput = AWSDynamoDBListTablesInput()
print("listing dynamoDB tables..")
let finalTask = dynamoDB.listTables(listTableInput).continueWithBlock{ (task: AWSTask!) -> AnyObject! in
if (task.error != nil) {
// failed to retrieve identityId.
if let handler = completionHandler {
print("Store Data Error occurred: \(task.error)")
handler(false)
}
return task
} else {
print("Store Data Succeeded...")
let listTablesOutput = task.result as! AWSDynamoDBListTablesOutput
for tableName : AnyObject in listTablesOutput.tableNames {
print("\(tableName)")
}
if let handler = completionHandler {
handler(true)
}
return task
}
}
以及在 DynamoDB 调用之前检索身份的代码:
func getAuthCognitoId(email: String, password: String, identityProvider: MyIdentityProvider)->AWSTask! {
identityProvider.email = email
identityProvider.password = password
// TODO: Store to a keychain
let task = identityProvider.getIdentityId().continueWithSuccessBlock() { (task) -> AWSTask! in
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: AWSRegionType.USEast1, identityProvider: identityProvider, unauthRoleArn: Constants.ARNUnauth.value, authRoleArn: Constants.ARNAuth.value)
let defaultServiceConfiguration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: credentialsProvider)
AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = defaultServiceConfiguration
return task
}
return task
}
编辑 2015 年 12 月 8 日:
我在我的lambda函数前添加了API网关,仍然无法获得授权角色。它成功检索到令牌和 idenityId,但是:
override func refresh() -> AWSTask! {
let task = AWSTaskCompletionSource()
let request = AFHTTPRequestOperationManager()
request.requestSerializer.setValue(email, forHTTPHeaderField: "email")
request.requestSerializer.setValue(password, forHTTPHeaderField: "password")
request.GET(Constants.loginUrl.value, parameters: nil, success: { (request: AFHTTPRequestOperation!, response: AnyObject!) -> Void in
print("request: ", request)
// The following 3 lines are required as referenced here:
self.logins = [self.developerProvider: self.email]
// Get the properties from my server response
print("response: ", response)
let identityId = response.objectForKey("identityId")as! String
let token = response.objectForKey("token")as! String
// Set the identityId and token for the ExampleAppIdentityProvider
self.identityId = identityId
self._token = token
task.setResult(self.identityId)
}, failure: { (request: AFHTTPRequestOperation?, error: NSError!) -> Void in
task.setError(error)
})
return task.task
}
问题是您使用未经授权的凭据调用 lambda
let lambdaInvoker = AWSLambdaInvoker.defaultLambdaInvoker()
由于它将这些凭据存储在钥匙串中以供后续请求使用,并且仅在它们过期时刷新它们,因此您在调用 DDB 时仍在使用未经授权的凭据。尝试使用 api-gateway 对您的 lambda 身份验证进行前置,这样您就不需要像您的评论中提到的那样使用 unauth 凭据开始,如果您仍然有问题,请告诉我。