使用Auth0控制对新AWS API网关HTTP API的访问

2020-05-29 07:49:49

几周前,AWS API Gateway HTTP API正式上市,提供了一种更简单、更快、更便宜的API构建方式。简化的功能之一是整个授权案例,这也是我们将在这篇博客文章中介绍的内容。

对于传统的RESTAPI,您通常会使用Lambda函数编写自己的Custom Authorizer来支持JWT授权(主要是在OpenID Connect和OAuth 2.0的上下文中)。HTTP API不再需要这样做,因为它提供了开箱即用的JWT授权器。

这意味着您可以通过提供3个简单设置来配置您自己的JWT授权器,而不必部署和维护您的自定义授权器:

让我们看看如何将Auth0配置为JWT授权程序。我们将构建一个简单的API,使用公共端点和私有端点返回颜色,要求用户首先进行身份验证。

在您的帐户中,您将希望将HTTP API表示为Auth0中的API,您需要为其指定名称和标识符。标识符最终将成为您的JWT Authorizer的受众。

我还将在Applications下创建一个单页应用程序,因为我将编写一个小的Reaction应用程序来与HTTP API交互。另外,这里的配置相对简单。

我们将在Auth0端做的最后一件事是编写一条规则,该规则将向access_Token添加一些自定义声明:

函数(用户、上下文、回调){上下文。accessToken[';http://sandrino/roles';]=[';admin&39;,';Member';];上下文。accessToken[';http://sandrino/email';]=用户。电子邮件;上下文。accessToken[';http://sandrino/email_verified';]=用户。电子邮件已验证(_V)。toString();返回回调(null,user,context);}

而这实际上就是它的全部。让我们继续讨论HTTP API。

有很多资源(auth0.com博客上的示例)向您展示了如何在AWS控制台中配置JWT授权程序,因此在这篇文章中,我们将使用无服务器框架。

我的API启用了CORS,因为我们希望浏览器能够与其交互。

Auth0被配置为授权者,只需提供我们在Auth0仪表板中创建的API的颁发者URL和受众。

我们有两个端点:/Colors,它是公共的(没有配置授权者),以及/my/profile,它将授权请求。

服务:HTTP-API-JWT-示例提供程序:名称:AWS运行时:nodejs12.x httpApi:CORS:alloweHeaders:-Content-Type-Authorization AllowedMethods:-Get-Options AllowedOrigins:-http://localhost:3000 payload:';2.0';授权者:accessTokenAuth0:IdentitySource:$request.header.Authorization IsorerUrl:https://sandrino.auth0.com/Audience:-urn:Colors-API函数:#列出所有颜色(公共端点)getColors:Handler.Colors事件:-httpApi:Method:Get Path:/Colors#列出我的配置文件(需要授权)myProfile:Handler.myProfile Events:-httpApi:Method:Get Path:

如果我们应用此配置,您将在您的AWS控制台中看到一个新的JWT授权程序:

在Auth0中使用自定义域时,应将该域配置为IssuerUrl。因此,例如,您应该使用https://auth.sandrino.dev/而不是https://sandrino.auth0.com/.

当为路由配置了JWT Authorizer时,您就不必担心解析和验证令牌了。如果提供了有效令牌,则声明将在事件中可用-否则请求将失败。下面是一个函数示例,该函数访问JWT授权程序提供的声明,并提取我们可能已添加的任何自定义声明(使用Auth0规则):

模块。出口。myProfile=异步(事件)=>;{常量索赔=事件。requestContext。授权者。JWT。索赔;返回{id:Claims。子角色:索赔[';http://sandrino/roles';],索赔};};

我们还将创建一个简单的Next.js应用程序,它使用auth0-spa-js从浏览器登录。

导入{}from';@auth0/auth0-spa-js';;export default new({DOMAIN:';https://sandrino.auth0.com';,//如果您已配置Client_id:';z9p3mE4Oc1PN4XKooapkPpn22nRONdJC';,Audience:';urn:Colors-api';,//这应该是的受众,则应为您的Auth0域或自定义域。OpenID配置文件电子邮件';});

在用户登录之后,我们将使用一个Reaction钩子从我们的API中获取数据:

EXPORT DEFAULT()=>;{const{data,error,isending,get}=useApi(Process.。环境。API_Gateway_BASE_URL);const getColors=()=>;get(';/Colors';,{auth:false});const getMyProfile=()=>;get(';/my/profile';);return(<;>;<;mb={5}isInline Spacing={4}>;<;size=";md"。onclick={getColors}>;<;/>;<;size=";md";onclick={getMyProfile}>;<;/>;<;/>;<;code={(待定&;&;&39;//正在加载.';)||(错误&;&;。stringify(error,null,2)||(数据&;&;。stringify(data,null,2)||';//按上面的一个按钮调用API Gateway';}language=";json";/>;<;/>;);};

useApi是一个自定义的反应挂钩,它从auth0-spa-js检索access_Token并将其附加到HTTP请求的Authorization头。实现可以在示例项目中找到。

但是,当我们确实通过Auth0登录并且Access_Token在HTTP请求中提供时,JWT Authorizer将允许请求通过我们的处理程序:

您会注意到,这里的颁发者设置为https://auth.sandrino.dev/,因为我正在使用我的Auth0自定义域执行所有测试。

在每个路由上,您还可以选择配置授权作用域,从而允许您定义令牌中应该存在哪个作用域来访问API路由。在下面的示例中,您可以看到我现在需要新端点的Read:Colors作用域:

如果您正在使用无服务器框架,您只需将所需的范围添加到您的路由即可:

myColors:Handler.myColors事件:-httpApi:Method:Get Path:/my/Colors Authizer:Name:accessTokenAuth0 Scope:-Read:Colors。

您的lambda函数不需要更改代码,一切都由JWT Authorizer处理。您需要做的唯一更改是在客户端请求此作用域:

导入{}from';@auth0/auth0-spa-js';;export default new({DOMAIN:';https://sandrino.auth0.com';,//如果您已配置Client_id:';z9p3mE4Oc1PN4XKooapkPpn22nRONdJC';,Audience:';urn:Colors-api';,//这应该是的受众,则应为您的Auth0域或自定义域。OpenID配置文件电子邮件内容:Colors';//我们在此请求额外的作用域});

真正有趣的是与Auth0';的基于角色的访问控制功能的链接,在那里我们可以使用角色和权限控制对特定范围的访问。让我们来看一个例子。在API上,我们将配置一个新的Read:Colors权限:

作为这项工作的一部分,我们还需要为API启用授权策略(启用RBAC切换)。这将要求用户具有正确的权限集:

启用此设置时,用户需要具有“读取:颜色”权限,否则将不允许该作用域。因此,即使客户端请求OpenID配置文件电子邮件Read:Colors,令牌最终也将如下所示:

{";http://sandrino/email";:";[email protected]&34;,";http://sandrino/email_verified";:";true";,";iss";:";https://auth.sandrino.dev/";,";sub";:";auth0|593b80d5f8a341400599ce4f";,";aud";:[";urn:Colors-api";,";https://sandrino.auth0.com/userinfo";],";iat";:1590666735,";exp";:1590753135,";azp";:";z9p3mE4Oc1PN4XKooapkPpn22nRONdJC";,";Scope";:";openid。

请注意,Read:Colors作用域是如何不存在的,即使它是由客户端请求的。

因此,对我们创建的新端点的调用将失败,因为我们的令牌缺少正确的作用域:

让我们继续在Auth0中创建一个角色,我们将向该角色添加Read:Colors权限。通过将权限添加到此角色,分配了此角色的任何用户都将能够接收Read:Colors作用域。

现在,当用户登录时,您会注意到一个重要的差异,即Read:Colors范围可用。

{";http://sandrino/email";:";[email protected]&34;,";http://sandrino/email_verified";:";true";,";iss";:";https://auth.sandrino.dev/";,";sub";:";auth0|593b80d5f8a341400599ce4f";,";aud";:[";urn:Colors-api";,";https://sandrino.auth0.com/userinfo";],";iat";:1590678148,";exp";:1590764548,";azp";:";z9p3mE4Oc1PN4XKooapkPpn22nRONdJC";,";Scope";:";openid。

当我们尝试访问新端点时.。它起作用了!。在所需的范围内,我们可以呼叫新路由:

您的用户需要从Auth0中收回一个新的访问令牌,这样的更改才会在您的应用程序中生效。这可以通过再次登录、通过静默身份验证(使用IFRAME)或使用刷新令牌来实现。

正如您已经看到的,使用JWT Authorizers可以非常容易地涵盖API Gateway的授权方面。虽然本文关注的是最终用户身份验证,但同样的ACCESS_TOKEN和Scope概念也适用于代表您的API与您的API对话的应用程序。

在GitHub上可以找到无服务器框架项目和Next.js应用程序的完整示例。