跳转至

什么是OAuth 2.0?

大多数应用程序都有用户的概念。为了防止任何人说他们是该用户,用户有一个密码。当用户想要使用你的应用程序时,他们会将自己的用户名和密码发送给服务器,这样服务器就可以确保他们是自己说的那个人。

做到这一点的简单方法是在每个请求的授权头中发送用户名和密码。这有两个原因是不好的:第一,每次用户想做什么事情,他们的密码都会在每次请求中发送,这可能是不安全的。第二,任何想要保持用户登录的应用都必须存储这个密码--这也是不安全的。

在OAuth 2.0中,用户将他们的用户名和密码交给客户端应用一次。应用程序将这些凭证发送到服务器上,服务器再给应用程序一个访问令牌。访问令牌是一个长的、随机的字符串,没有人可以猜到。当用户想做更多的事情时,应用程序会在每次请求时发送令牌,而不是用户的密码。服务器会检查令牌,确保它没有过期,然后让应用程序的请求通过。应用程序不需要存储密码,也不需要再次询问用户的密码。

这种凭证换令牌的交换是通过向某个终端发送POST请求来实现的,用户名和密码会在请求正文中发送。通常情况下,Aqueduct应用程序的路由是/auth/token,由AuthController的一个实例处理。

OAuth 2.0做了一个微妙的区分:用户和他们所使用的应用程序不是一回事。直观地认为用户是 "向服务器发出请求",但实际上,用户向应用程序发出请求,而应用程序向服务器发出请求。服务器代表用户授予这个应用访问权限。换句话说,当用户在应用程序中输入他们的凭证时,应用程序会对服务器说:"嘿,这个用户说我可以为他们做一些事情。看,这就是他们的秘密密码!"

这是一个重要的区别,因为OAuth 2.0服务器不只是验证用户:它还验证应用。一个应用程序有一个已经在服务器上注册的标识符。因此,对于一个有web客户端、Android和iOS应用的生态系统来说,很可能有三个标识符--每一个都有一个。客户端应用程序通常会将该标识符存储在数据库中。这个标识符被称为客户端标识符。客户端标识符是通过aqueduct auth工具添加到Aqueduct应用程序中的(参见Aqueduct Auth CLI)。

当用户通过应用程序登录时,他们会提交他们的用户名和密码。用户并没有提供客户端标识符--事实上,用户并不知道它。应用程序发送请求时,在请求正文中包含用户的用户名和密码,在授权头中包含客户端标识符。这三者都要签出,服务器才能给应用回馈给应用一个令牌。伪代码中的完整请求看起来是这样的:

var request = HTTPRequest("/auth/token");
request.method = "POST";
request.contentType = "application/x-www-form-urlencoded";
request.authorization = Base64.encode("$clientID:");
request.body = {
  "username" : "bob@stablekernel.com",
  "password" : "supersecretstuff",
  "grant_type" : "password"
};

访问令牌可以过期。过期时间由服务器决定 - Aqueduct默认为24小时。乍一看,这意味着应用程序将不得不再次向用户索要密码。但是,令牌也可以刷新。刷新令牌可以授予一个全新的访问令牌,但不需要询问密码。这是可能的,因为一个访问令牌带有一个刷新令牌。刷新令牌是另一个长的随机字符串。因此,服务器在授予令牌时发送回来的JSON是这样的:

{
  "access_token" : "Abca09zzzza2o2kelmzlli3ijlka",
  "token_type" : "bearer",
  "refresh_token" : "lkmLIAmooa898nm20jannnnnxaww",
  "expire_in" : 3600
}

应用程序会同时挂载一个访问令牌和一个刷新令牌。当令牌过期时,它将把刷新令牌送回服务器以获得一个替换的访问令牌。这是通过与访问令牌相同的途径来完成的 /auth/token 只是参数有点不同。

var request = HTTPRequest("/auth/token");
request.method = "POST";
request.contentType = "application/x-www-form-urlencoded";
request.authorization = Base64.encode("$clientID:");
request.body = {
  "refresh_token" : "lkmLIAmooa898nm20jannnnnxaww",
  "grant_type" : "refresh_token"
};

交换一个刷新令牌与初始交换用户名和密码的响应是一样的, 除了一些值发生了变化。

授权和认证信息的验证和存储由AuthServer管理。

获得授权的其他方法

上面的获取令牌的方法 - 将用户名和密码发送到/auth/token - 只是OAuth 2.0用来验证用户的四种可能的方法之一。这个特殊的方法被称为资源所有者密码凭证授予。资源拥有者是一个 "用户 "的花哨词。我们可以把它简称为'密码流即可。这可能是最常见的流程----手机应用和前端Web应用经常使用这个流程。当你输入凭证时,客户端应用程序直接将其发送到服务器。

另一种常用的流程是防止客户端应用程序看到用户的凭证。例如,您可以用您的 Google 帐户登录到 Pivotal Tracker。您在Pivotal Tracker上的账户没有密码。相反,它被链接到您的 Google 帐户,而 Google 帐户有密码。Pivotal Tracker 永远不会看到您的 Google 密码。当您以这种方式登录Pivotal Tracker时,它会将您带到Google的认证页面--由Google拥有和运营。当您成功登录后,谷歌会将您的令牌交给Pivotal Tracker。Pivotal Tracker现在是一个可以代表你做事情的应用程序。

这就是所谓的授权码授予或者说是“验证码流”。一个 AuthCodeController的实例来处理授权代码的授予。一旦收到一个代码,它可以通过AuthController来交换一个令牌。