Oauth 2.0 我是否在做整个API、客户端应用程序、Oauth/OpenId连接的事情?

Oauth 2.0 我是否在做整个API、客户端应用程序、Oauth/OpenId连接的事情?,oauth-2.0,jwt,web-deployment,openid-connect,Oauth 2.0,Jwt,Web Deployment,Openid Connect,我有一些编程经验,但仅限于PHP和Java企业系统。但现在我对新工作中的网络应用有了一些想法。因为我是新手,所以我想分享一下我是如何使用谷歌的OpenID Connect在服务器、浏览器应用程序和身份验证中完成整个API的(我读了很多关于Oauth和OpenID Connect的文章,最有用的来源是:) 服务器:Laravel-hxxps://coolapp-api.mycompany.com 客户:角度-hxxps://coolapp.mycompany.com TL;DR版本: 1) 用户转

我有一些编程经验,但仅限于PHP和Java企业系统。但现在我对新工作中的网络应用有了一些想法。因为我是新手,所以我想分享一下我是如何使用谷歌的OpenID Connect在服务器、浏览器应用程序和身份验证中完成整个API的(我读了很多关于Oauth和OpenID Connect的文章,最有用的来源是:)

服务器:Laravel-hxxps://coolapp-api.mycompany.com

客户:角度-hxxps://coolapp.mycompany.com

TL;DR版本: 1) 用户转到hxxps://coolapp.mycompany.com,获取一个Angular应用程序登录页面。键入他们的电子邮件,点击“登录谷歌”

2) 应用程序将电子邮件发送到hxxps://coolapp-api.mycompany.com/api/sign-in. 服务器将用户重定向到hxxps://accounts.google.com/o/oauth2/auth 具有所有需要的参数

3) 用户登录到他们的谷歌帐户,如果这是他们第一次使用我的应用程序,谷歌会将他们重定向到我的服务器hxxps://coolapp-api.mycompany.com/sign-in/google/callback. 服务器会检查所有内容,如果都正确,它会创建一个JWT令牌,并向位于的客户端应用程序发送重定向hxxps://coolapp.mycompany.com/login/callback?token=JWT-代币

4) 客户端应用程序获取令牌,将其存储在本地存储中,并在每次API调用时将其发送到服务器

更详细的版本: 1) 用户转到hxxps://coolapp.mycompany.com,获取一个Angular应用程序登录页面。键入他们的电子邮件,点击“登录谷歌”

2) 应用程序将电子邮件发送到hxxps://coolapp-api.mycompany.com/api/sign-in. 服务器创建一个状态令牌并将其存储在缓存中,与收到的电子邮件关联。然后服务器创建Google的oauth URL并将其发送到响应体中的客户端。我试图通过HTTP重定向来实现这一点,但谷歌的服务器出现了CORS错误。Angular应用程序从响应中读取谷歌的url,然后转到那里

3) 用户登录到他们的谷歌帐户,如果这是他们第一次使用我的应用程序,谷歌会将他们重定向到我的服务器hxxps://coolapp-api.mycompany.com/sign-in/google/callback?code=AUTHCODE&otherstuff. 服务器将收到的代码(以及所有其他需要的参数)发送给hxxps://accounts.google.com/o/oauth2/token. 它接收带有该用户电子邮件和基本信息的id_令牌。这个应用程序不是公开的,所以我不想让任何有谷歌账户的人登录,只想让我将其电子邮件添加到服务器数据库的客户登录。因此,现在服务器检查用户在令牌中的电子邮件是否在数据库中。如果不是,则向用户发送HTTP 401-未经授权。然后,服务器检查其缓存中与接收到的电子邮件关联的状态令牌。如果它等于通过Google重定向接收到的,那么服务器将创建另一个JWT令牌,但现在由我的服务器签名。最后,它将HTTP重定向发送到hxxps://coolapp.mycompany.com/login/callback?token=JWT-使用新令牌创建令牌

4) 客户端应用程序获取令牌,将其存储在本地存储中,并在每次API调用时将其发送到服务器

一些评论:
  • 一切都很好

  • 我向我的Laravel服务器和Angular客户端添加了最严格的CSP策略

  • 目前,该应用程序仅支持谷歌的登录,正在开发中。稍后我将添加更多内容

  • 我让我的服务器只在用户登录谷歌后检查他们的电子邮件是否在数据库中,因为我喜欢非授权用户不应该有任何信息的想法。如果我在第一次往返旅行之前进行了检查,任何人都可以键入电子邮件并发现该电子邮件在我的系统中是否有帐户

  • 在最后一步中,当我的服务器将JWT令牌发送到我的客户端应用程序时,我尝试在cookie中发送令牌,但由于我的API和客户端应用程序具有不同的域,因此客户端应用程序无法读取令牌。在url中发送它是我能找到的唯一解决方案。我尝试登录一个使用Oauth的流行应用程序,他们也是这样做的

所以我的问题是:

我是不是做错了什么,不安全的,奇怪的

非常感谢大家

1)每次用户想要登录时输入电子邮件地址都很乏味。如果用户已经登录到谷歌,则不需要它。用户只需单击“使用谷歌登录”按钮即可登录,无需输入任何内容。状态参数可以是随机字符串-与用户的电子邮件没有任何关系

2) 如果您希望您的后端处理来自Google的重定向(使用身份验证代码流-后端在OAuth2术语中具有客户端角色),那么后端还应该启动到Google的重定向-而不是通过发送包含重定向URL的数据。要实现这一点,在单击“使用Google登录”按钮后,执行整个页面导航(而不是XHR请求)到
/api/登录
,如果后端返回HTTP 302,浏览器将正确重定向到Google

3) 在获取令牌并检查用户是否存在之前,您应该执行请求验证(state参数)。 在错误(拒绝访问)中,您可以考虑将用户重定向到具有错误细节的错误页面,而不是返回HTTP 401,因为HTTP代码将导致向用户显示通用错误屏幕。如果您想继续使用HTTP代码,我认为这更合适

4)考虑使用SeScess存储代替本地存储。关闭浏览器/选项卡后,会话存储将被清除,并且不会在选项卡之间共享。它使它更安全,并允许用户在不同的浏览器选项卡中使用不同的标识。 您的后端问题的令牌,其有效期是否有限制?用户是否需要在一段(短)时间后获得新令牌?否则,有效的令牌值可能会保留在localStorag中