AWS Cognito包含User Pool和Identity Pool两个产品。基于User Pool可以快速实现一套用户系统。Identity Pool用于实现联合身份认证。User Pool跟Identity Pool的关系如下面几张图所示。
通过AWS labs的demo可以体验Cognito的主要功能,github地址:https://github.com/awslabs/aws-sdk-ios-samples。
User Pool
aws-sdk-ios-samples里面CognitoYourUserPools-Sample
和CognitoAuth-Sample
两个demo跟User Pool里面有关。要把这两个demo跑起来,要先在User Pool里面添加一个pool,接着添加一个App,再接着修改项目里面对应的配置。
CognitoYourUserPools-Sample
支持注册、登录、找回密码等功能。
还有更简单的使用方式,那就是User Pool会提供一个OIDC server。
https://wla.auth.ap-southeast-2.amazoncognito.com/login?
response_type=code
&client_id=1t80si9ch1voi0bdusm5c9svn
&state=00a4715e-13b3-4da3-8553-dcc757d1d544
&redirect_uri=wla://signin
&scope=openid
&code_challenge=CHdOC4yZEQWOg3jZNCTm8b8v8jPnKjizRipIF0ltvr8
&code_challenge_method=S256
在控制台可以配置icon、前景色和背景色。之后点击Sign in
按钮,会在In-App browser里面打开下面这个页面,挺好看的。
看起来这是一个标准的OIDC服务器,可以看看它的Discovery,然后就会发现其实也不是那么标准,里面有authorization_endpoint,并没有看到token_endpoint。看demo里面的玩法就更野了,根本不来请求这个Discovery,而是要使用Info.plist里面的AWS
的配置去拼这些endpoint。
上面两个demo中都可以注册账号,可以在控制台里面看到这些账号。
为了满足用户多样的需求,User Pool在很多环节都可以设置Lambda function,非常有用。
Identity Pool
CognitoSync-Sample
这个demo是展示Identity Pool功能的,这个demo就有点太粗糙了,居然也没有加入User Pool登录。
我配置了一下Facebook登录,登录了一下试试,感觉还挺溜。
token
User Pool登录成功得到的信息如下所示。看起来是OAuth那一套,这个AccessToken很长,是一个JWT Bearer Token,跟IdToken信息有重叠。这两个token都可以拿到https://jwt.io里面解开看看。具体的描述请参看:Using Tokens with User Pools。
{
"AuthenticationResult": {
"AccessToken": "eyJraWQiOiJicVQ4ZkViVzJCbXN2blZwcGRlUWQ0REhKaTZjdzNNZGhaTzJrN2s3c2w0PSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiI4NzI2ZmFjZi1jNjNmLTRlNDQtOGM1YS1jOTE5YjdjNTMxMDYiLCJkZXZpY2Vfa2V5IjoiYXAtc291dGhlYXN0LTJfZjY1MjY0NjktNjBhMi00ZWUyLTk5MTMtNzAyYmE3NTllMjdjIiwidG9rZW5fdXNlIjoiYWNjZXNzIiwic2NvcGUiOiJhd3MuY29nbml0by5zaWduaW4udXNlci5hZG1pbiIsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC5hcC1zb3V0aGVhc3QtMi5hbWF6b25hd3MuY29tXC9hcC1zb3V0aGVhc3QtMl9IbkdrZVh5YUIiLCJleHAiOjE0OTgyMzU4MjEsImlhdCI6MTQ5ODIzMjIyMSwianRpIjoiNjcyMmUyM2EtMmQ4Mi00YTg2LWE1NWYtZjRjNjRjYjZmMTQ2IiwiY2xpZW50X2lkIjoiMXQ4MHNpOWNoMXZvaTBiZHVzbTVjOXN2biIsInVzZXJuYW1lIjoiaHMwMDIifQ.ONnjTQr0Qd2AaKCxfnBKT3TnMu-k8Jf_awBapH2A3QpzSIBBBYo3lQzL20JMP92gFfwho9XQGsUjPwNMfkIl19YZG_8BZSME1Aw6l9LT5Q35pGBiuaq1A82rOGmmfgS35RYQ25YxeF18_vO6e4gYdxvAHMSrK8zIJQvFWV6wQYkRpucphKg7bCrmdW5mJt_QyC64JA3JYuHGW2bkFM7IsTt9eop5igIxQTp7uR8oWsSLeYAsJ2nkAdRkbvVt1XvqNmFCU8iOIF0rtkm6bKGdYQprlxAHvyxFVTVBJt-42UWWGII7YaYQTF8k7Lhzu6HAlU27KzlSZ2279CVGKw2BVQ",
"ExpiresIn": 3600,
"IdToken": "eyJraWQiOiJlaFNtY1pjM1JBdEhGYkVWVFpucFBDNWZTSFwvSW15dUN1cmRHUk0wcUVrST0iLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI4NzI2ZmFjZi1jNjNmLTRlNDQtOGM1YS1jOTE5YjdjNTMxMDYiLCJhdWQiOiIxdDgwc2k5Y2gxdm9pMGJkdXNtNWM5c3ZuIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJ0b2tlbl91c2UiOiJpZCIsImF1dGhfdGltZSI6MTQ5ODIzMjIyMSwiaXNzIjoiaHR0cHM6XC9cL2NvZ25pdG8taWRwLmFwLXNvdXRoZWFzdC0yLmFtYXpvbmF3cy5jb21cL2FwLXNvdXRoZWFzdC0yX0huR2tlWHlhQiIsInBob25lX251bWJlcl92ZXJpZmllZCI6dHJ1ZSwiY29nbml0bzp1c2VybmFtZSI6ImhzMDAyIiwicGhvbmVfbnVtYmVyIjoiKzg2MTg5MDU4MTgyOTIiLCJleHAiOjE0OTgyMzU4MjEsImlhdCI6MTQ5ODIzMjIyMSwiZW1haWwiOiJjcWZ6am5lQGdtYWlsLmNvbSJ9.eV9osb4FQUAzCf4bDFGH9SHwuelC1v78oenxINihVGZ7aqJ82sozfSPtMMcsjN9sm32RZajoyBkw9Buni_bywwjv5FtVgoLb3aXkSvHxtNrXyT1Ligym2c3NJvsEC2aiVr5DFBIEZieSwdsLajcM5JSk9KYgO5OAiTuIe_TiKom2lfm7-n_uF0b09Z3GuYqHXkvufxJnXzb3gqxeY1_M6g3BqEu3Nta-kGqabzn_-6JsYgDY14jyBwRrydMqUqjfZjjLRgZxHBitWMWz0dp4wrTpHOGktqtVdjhj9m8-p4IXp-za3ADcoBh5QSCX49loHi2Mm45gfFiyEVLC3X4P7Q",
"RefreshToken": "eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.VFeqGiKV-fH8uTpoihvbyS7FVcdPGiSQVZzf9CWL6UfD3ucm5RaL_J0Sm6kh_0T86gZJQdO1nZ2BBongemyipzSvrowOTUqnqk5sE-5mTU6VXZYzRevhnm-Gr2sF7o0Dx4IrI8Esjn2K0KMZx2TLGHGAHRvFTG5kmFJNR_80o9VRMXaN1X_1LEuJF58amfj1lMqUq0lWoLmWBb5AaCnfap3DuIBxq_egFTgV-JvhlZaHD9Y6L8RANh6Rv2YunCYdyMs8Dw8H7HZHSm5hSdB1sIh-e1M6PMVX-i0V_3R6_IkU0qnC_0NTQw_MvZFO6psjDKCNejAAbvMDoJO6zJsDVQ._B25kR6-WKz3zzJW.-5Xv72tm6qz-gnm2Ojf5QfSxGqFsvl_DlSqgHbYLaUJJLcjKlQGH1uhSohaivadFKT29cdoRH-rHATCSQuzia1RyiMXfYtF2a2DLv3gErS6Rgd4EyZWvddLTjWi0-QdrXvEp5Ry1P_2jakp7_Ng4vKRuvkm9kDHTeeLdLEwDIBJXNGXvIx7qHLBDaBbcP2O9ayU0vVSM3WdzkaHe2-hCEvaHe5w9ygLrzqEdpxv1MsP1botJcBPiBFIPCt-29EKMLoDNC9PU8jczJuGwqcGINuYt9S9kh6JMLw-rpX6wofX4h_B6uy8zEiN6JhQWIv4incFvJBjK1z5v8N51gcT3U1yzNtkeImiU8R-SWPl2gTp3SxguK_-FxhjBuQOHv8v1n_NMYkKz7PchFv77TVBEVDFmNg0cdB2gMhV2yk8x_HbNK5ttOncpN_sLDR1YML3YwIRjiWAz4cyCM6oAGOkSEFwkFcwqHy8PtLdXH2rxxhopUfGJAAUJdpxWC_NpoJFvrBT20794sUMEBRU9BBudsTargWSDZaycgYJN-VxYmFIfoqkejJt9iFs8XGZpx0Uz8qMxNic7g-Kl2CMtht5dgK-_DTlqity6d3CQe3kVjabmoVEwfniopEo_y_Uv7tICgAMc2ScOjg-YjFO3oKzdeOejlEmXV0EvivtICR-QChlqN-XlvWebwdruX6xkyYVh6Js12cH-V40Ll8PEaBVpIOlDe5hz53feR3X9hKmfbAqSZVp0Uk9fh_MJf7vh3XnHyamnTTpn4f-0q9lzHwbt6iiN4vxhCoePVwzLCl4FZFllO0XwVJJmhjCc9YbsIgV6BANjLjyHo5pmb8FfjrP95m5vJVHjRztNeYkr6njCL1rkNwxeAjXahPLKGyyyuIqEPfejWHIJJ7-HUfuof3SOwDVjXRK4j7rHpCMAVGUCWzffPtN4rFPqGNUHFMtXW2J05ydCXBXdHgA4WdbfYkrwSbSY51wLU_PW9RUubbAf0P9MS680TdyjZNfavy6l9LiMFfkwXAbVb0lFBbFzMzHRKotBdoJcr01RT2Kz8JOlihsFRDqXb-V0Z06Tku63uO23z9Usyxp3am8tnYhlBBrYe0L_cdRgEXqtSBipKchwfojsQh-uPzbzLX95XSMlLdedcSJSicaeT2VZqt8l-nJzXcGWQ9nFZxdzlT_XA-44hS-o8u1OrIvw_OlFyBd1KFAC5KBCu4SskkQWqg9iAH3Rn33mVGJqf8hcuSVKTYQ3YFyD8yvTmZOHYFnPW7Yc7Ecrg0-s4yXL._4s3xxrYlVU-0LPaIB6Auw",
"TokenType": "Bearer"
},
"ChallengeParameters": {}
}
解开IdToken之后,看看里面的iat
和exp
,可以发现IdToken的过期时间是一个小时。
Identity Pool登录成功之后得到的信息如下所示。看起来就是STS token啊。
{
"Credentials": {
"AccessKeyId": "ASIAI46U752A4IDXV2TA",
"Expiration": 1498235294,
"SecretKey": "rj6Kd07s1lbTpRNOXBNdzxxCY56G2jRN26yddHcW",
"SessionToken": "AgoGb3JpZ2luEIP//////////wEaDmFwLXNvdXRoZWFzdC0yIoACNsPwXYx/zmX42sN3HEEHw/cY0yzELJdHTsF+C+HpUnbklUOmxTvgWIQ8/rVnUGWewsSrazIA5idbm4Chb2OAaPDKlGuAfq/ovZZS2HIhMWFBPnWzFggOsDlqe73QVhw96RW8t8dACTuoNEZjAlXPIPk90oZXHRctEiPr/vrzJYWy5M39RxgY3lxKAe3cosbIJhSARxIxuaudueYdC96xxQXSjQMn7sA5VGsjnU9hytgni4sDR0ozFUlfKi7OhuylKTiB5zIWaMmDnyt+SKfoC506RNPH/QNu3PLLqSUgVG6yMov0Eydub6T66lZgkDDYTmwmgKjze0Pd9aVw0qrapyrdBAjZ//////////8BEAAaDDk3ODM0MzM3MDU3NyIMMF7ptJyDwDX5/6gSKrEE3beePMNROAKR1bB54f+xnvo8ZUryymf430PkKHC3Q0oW1+eeBi44F1raX/Bv4tlq6WWK3RlrFl+gPNLeZC/b9xcyJI2q4luMBwYAbqXHKYJxwzlIhXHGjqxf27/01X9ksK3X8nove2y51TK84MHzxQjm4ABQfE2873mSS1YIbTgOBV7jDYn91pal4lXIrUilQIw1GUQ5m+SSHKfbpzwZpWTbnYesrXfWRd59pYaQ6yntat1/La/mZG5i/Dbk+HUOieyAGffMt5OICB75JpUkRjyMo8qNkdc4/nsEvMNTLl1LQdhVL6zmkKdztNZBbn76Uz1cr7u1sOJLCqHKY5P2uNuGvA11YaJN9MGLJwI+VNSGiDD7hT8Sor2bMHd3r9hy+SGAUfyhjPtch5D8tHwYTT/1GyBLyN2ws7ym/dYxHJ+4gpjK78J7VCjdR1BN5amtQTgzrZ9kjS7SkhVPVLxNJK3+GTk6M5asitd1V/BRwpBHtS1LCFqYAGdlOADVl+TKgo15OmATY9aKmwUoYQpZKV9cvk2ferOGCQwfv92F5QSqxGibb0+8/rJF4CIfpneXp2YLRu07FubicyhLa+pWuMJ5IwC2b6pbZho212PIjuuBrlH+TDEKNF6aC7f4RRnk87A/Chsgq32KxUZVgt5MtOr3LPrMmU1hB28yqb0ofabMq14o3vAgY3+SPa5NBWxQxhO/YN+vB9Y4J+I+p0dxb7amWQNzJLuCURUoK8RT0qfbMI7ntMoF"
},
"IdentityId": "ap-southeast-2:65d024cf-f342-4c5d-8ece-7d1736d24633"
}
IAM
User Pool和Identity Pool怎么跟AWS IAM关联起来呢?那就是配置role。User Pool可以创建group,然后把用户加入到group里面,而group可以设置role。详细的描述请看文档:Assigning IAM Roles to Groups。
Identity Pool同样可以创建和指定角色。
这些角色在AWS IAM里面都可以找到。但是User Pool和Identity Pool自己并不会出现在IAM的用户和组里面。
我有一个疑问是,如果一个账号在User Pool里面的角色是A,然而Identity Pool使用角色是B,那么我在Identity Pool里面登录了这个账号,那么他对应的角色是A还是B呢?还是拥有两个角色所属权限的交集或并集?
最后的总结
User Pool貌似是配合AWS API Gateway一起使用的。毕竟OAuth/OIDC这套东西非常成熟和标准,适用于HTTP协议下。
A user pool is integrated with an API as a method authorizer that
is applicable for any method. When calling the methods with such
an authorizer enabled, an API client includes in the request
headers the user's identity token provisioned from the user pool.
API Gateway then validates the token to ensure it belongs to the
configured user pool and authenticates the caller before passing
the request to the backend.
To integrate an API with the Amazon Cognito identity provider,
you, as an API developer, create and own a user pool, create an
API Gateway authorizer connected to the user pool, and enable
the authorizer on selected API methods. You must also distribute
to your API client developers the user pool ID, a client ID, and
possibly the associated client secret that are provisioned from the
user pool. The client will need this information to register users
with the user pool, to provide the sign-in functionality, and to have
the user's identity token provisioned from the user pool.
接着去AWS API Gateway里面看看。我发现在Authorizers里面可以指定使用Cognito User Pool Authorizer
。
Identity Pool给的就是STS token,所以可以直接拿去访问AWS Service。
Amazon Cognito Federated Identities enable you to create unique
identities for your users and federate them with identity providers.
With an identity, you can obtain temporary, limited-privilege AWS
credentials to synchronize data with Amazon Cognito Sync, or
directly access other AWS services.
使用API Gateway
User Pool的id token可以用来调用API Gateway的API。API Gateway可以设置custom authorizer,这是一个User Pool。如果一个id token对应的用户属于这个User Pool,那么拿着id token就可以访问API。AWS也支持通过Identity Pool的方式来调用API Gateway,这样做会麻烦一些,需要使用API Gateway生成的接口SDK,配合相应的IAM role,才能调用成功。
首先在API Gateway复制PetStore这个API。
在
Authorizers
里面创建一个Cognito User Pool Authorizer
,选择好region和User Pool。
- 设置好之后,可以验证一下id token。id token可以从
CognitoYourUserPools-Sample
demo的日志里面获取。如果id token这个用户不属于wla-demo
这个User Pool,那么验证会失败。
- 对
pets
的GET接口设置Authorization,选择上面创建好的custom authorizer。
- 发布接口之后。在Postman里面做测试。HTTP Header里面设置
Authorization
为id token即可。如果只是设置一下HTTP Header,通过curl也可以做到,哈哈,用Postman牛刀杀鸡了。
- 如果不设置
Authorization
,那么会提示如下错误。
对于整个流程下面几张图也有比较好的阐述。
最后简单总结一下吧。我觉得User Pool是一个完整的用户系统,实现了OAuth 2.0,并且支持SAML做SSO。User Pool可以跟API Gateway联动起来,方便用户做一个完整的Serverless应用。而Identity Pool则支持主流的ID Provider,包括User Pool,用户认证之后颁发STS token,用于访问AWS自己的服务。在AWS服务的归类中,Cognito属于移动服务
这个类目下面。Cognito+API Gateway+Lambda function=Serverless,有这一套体系,加上AWS移动相关的SDK和服务,写一个App是一件非常惬意的事情。
参考资料
- Cognito User Pool vs Identity Pool
- Getting Started With Your User Pools In Amazon Cognito Slideshare
- Getting Started With Your User Pools In Amazon Cognito Youtube
- Securing Serverless Workloads with Cognito and API Gateway Part I
- Securing Serverless Workloads with Cognito and API Gateway Part II