我做了整个API、客户端应用程序、Oauth/OpenId连接的事情吗



我有一些编程经验,但只使用PHP和Java企业系统。但现在我对新工作中的网络应用程序有了一些想法。由于我是这方面的新手,我想分享我是如何在服务器、浏览器应用程序和Google的OpenID Connect身份验证中完成整个API的(我读了很多关于Oauth和OpenID Connect的文章,最有用的来源是:https://developers.google.com/identity/protocols/OpenIDConnect)。

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

客户:Angularhxxps://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&其他东西。服务器将接收到的代码(以及所有其他需要的参数)发送到hxxps://accounts.google.com/o/oauth2/token.它会收到一个包含该用户电子邮件和基本信息的id_token。这个应用程序不是公共的,所以我不希望任何拥有谷歌账户的人登录,只希望我将其电子邮件添加到服务器数据库的客户登录。因此,现在服务器会检查令牌中用户的电子邮件是否在数据库中。如果不是,它会向用户发送HTTP 401-Unauthorized。然后,服务器检查其缓存中与接收到的电子邮件相关联的状态令牌。如果它与谷歌重定向收到的令牌相等,那么服务器会创建另一个JWT令牌,但现在由我的服务器签名。最后,它发送一个HTTP重定向到hxxps://coolapp.mycompany.com/login/callback?token=JWT-使用新代币代币代币。

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

一些评论:

  • 一切都是HTTPS;

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

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

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

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

所以我的问题是:

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

非常感谢大家

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

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

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

4) 请考虑使用sessionStorage而不是localStorage。会话存储在关闭浏览器/选项卡后被清除,并且不会在选项卡之间共享。它使它更安全,并允许用户在不同的浏览器选项卡中使用不同的身份。您的后端问题的代币,它们的有效期有限制吗?用户是否需要在一段(短)时间后获得新令牌?否则,有效的令牌值可能会保留在localStorage和浏览器的页面历史记录中,这可能是一个安全问题。

您可以考虑使用您自己的OAuth2身份验证服务器(如RedHat Key斗篷),该服务器将接受谷歌(以及后来的一些其他提供商)进行身份验证,并且还将发布您后端接受的访问令牌。

相关内容

  • 没有找到相关文章

最新更新