Passport 之API令牌

吴举
2023-12-01
  • OAuth 与Passport

    • Session 技术都是结合客户端 Cookie 来实现
    • 从后端剥离出去的前端应用无法通过 API 请求从客户端传递 Cookie 及 CSRF Token 到后端
    • 即Api请求方式无法通过Session实现用户认证,客户端负责维护应用状态,而服务端维护资源状态
  • 前后端分离的API认证

    • 用户认证信息存储在后端网站,当前端需要访问认证资源时,通过后端应用授权的方式访问
    • 授权的前提是前端应用在后端应用注册过,否则不能授权,只有用户允许授权,才可以访问认证资源
      • 对于passport建立的oAuth服务,通常是用命令行passport:client注册第三方应用
        • 通常用户的资源在oauth服务器上
        • oauth根据用户id及其用户要授权的应用方生成 CLIENT_IDCLIENT_SECRET
        • 后续用户在第三方首次访问时,只需通过CLIENT_SECRET,来得到令牌
        • oauth方通过令牌可辨别用户及要授权的资源,给予第三方应用
    • 令牌访问认证 API
      • 确认身份,即必须备案,有记录可查的用户信息,以此维护用户的状态及数据信息
  • 常用的认证的类型

    • Bearer Token
    • Basic Auth
    • Digest Auth
    • OAuth 1.0/2.0
    • Hawk Authentication
    • AWS Signature
  • passport流程

    1. storage 目录下生成oauth公私钥 php artisan passport:install
    2. 修改认证模型类,使用 Laravel\Passport\HasApiTokens Trait
    3. API认证路由 Laravel\Passport\Passport::routes(),路由前缀为 /oauth
    4. 修改配置文件,将API认证驱动由token修改为passport

单页面应用API认证(Cookie授权令牌)

  • 场景
    • API 认证只用于客户端 JavaScript 与后端接口的交互
  • 单页面应用api认证
    • 在web路由组中新增\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,中间件
      1. 在用户首次通过 Web 页面登录表单登录后在 Cookie 中设置一个 Token
      2. 在用户访问需要认证的 API 接口时,走 auth:api 认证中间件,api认证驱动是 passport
      3. 在底层根据api 参数,针对 API 接口认证会通过 Laravel\Passport\Guards\TokenGuard 获取认证信息
  • TokenGuard看守器
    • 优先从包含 Bearer Authentication 请求头中获取Token 信息
    • 若无上,则从cookie中获取laravel_token,即 bearerToken > passport::cookie

移动端应用(密码授权令牌)

  1. 创建移动端应用
  2. 在后端应用(passport安装oauth服务的服务器)中注册移动端应用
  3. 配置移动端应用
  4. 在移动端应用填写登录表单进行登录
  5. 后端应用授权移动端认证
  6. 令牌有效期passport方法
    • 设置有效期 tokensExpireIn refreshTokensExpireIn
    • 刷新令牌 在oauth/token 路由请求中指定操作类型为 refresh_token 来刷新令牌
  • 应用场景
    • 公司自有系统之间如何通过用户凭证获取密码授权访问认证 API 接口

第三方应用(授权码获取令牌)

  • 前提
    • 第三方应用已知client_id,client_secret
    • 后端用到passort的 auth:api中间件
  • 应用场景
    • 支持第三方应用户接入获取认证信息
  • 密码授权获取令牌缺点
    • 若第三方应用不可信,把用户名密码信息记录下来,用户信息会被泄露风险
  • 授权码流程
    1. 在后端系统注册第三方应用
    2. 配置第三方应用
    3. 编写第三方应用路由和控制器
    4. 测试通过授权码获取令牌

开放平台(客户端令牌)

  • 客户端凭证令牌
    • 授权方式不需要走典型的登录或授权重定向流程,免去了跳转认证、重定向的复杂流程
    • 应用场景 适用于机器与机器之间的接口认证
    • 逻辑原理
      • 后端需用到passport自带的CheckClientCredentials中间件,通常别名为client
      • 在客户端应用中通过分配的 APP ID 和 APP SECRET 获取授权令牌,最后拿着这个令牌访问后端认证接口
    • 客户端令牌
      • 默认长期有效
  • 流程
    1. 在开放平台注册客户端应用
    2. 在客户端定义路由与控制器
    3. 访问开放平台认证接口

沙箱测试(私人访问令牌)

  • 授权特点
    • 用户给自己颁发访问令牌,无需授权码,亦无登录凭证
    • 应用于用户测试,平台体验
      • 即直接在后端(oauth服务器)上运行,可以管理用户所有令牌
  • passport 流程
    1. 后端系统注册测试应用 passport:client --personal
    2. 获取访问令牌
      • 后端认证的用户模型类必须使用了HasApiTokens Trait
      • 路由,控制器使用模型$user->createToken('Users')->accessToken
    3. 访问认证接口
      • 生成的令牌记录可以在 oauth_access_tokens 数据表中找到,私人访问令牌默认是长期有效的。

隐式授权令牌

  • 隐式授权特点
    • 不需要获取授权码,就可以将令牌返回给客户端,极度不信任第三方能够安全存储令牌
    • 适用于同一个公司自有系统之间的认证
    • 特别适合 客户端凭证不能被安全存储的移动应用或 JavaScript 应用
  • 使用流程
    1. 后端设置
      • 在后端系统 AuthServiceProvider 的 boot 方法中调用
      • 启用隐式授权令牌 Passport::enableImplicitGrant();
    2. 前端设置
      1. 后端注册后,前端CLIENT_ID 和 CLIENT_SECRET 配置
      2. 前端配置相应的路由,控制器
  • 特色
    • 确认授权之后,会根据当前url中的redirect_url跳转,并在url中以#锚点形式附加access_token令牌
    • 通过以锚点形式返回 access_token 的原因是不会把它们发送到服务器
    • 确保只有客户端才能解析上述锚点里的参数(你可以无论通过 Laravel 还是PHP 都解析不到 access_token)
  • 应用场景
    • 隐式授权令牌也可以用于单页面应用认证 API 接口访问
    • 在某些安全性要求比较高的场景下,不能在客户端存储令牌信息,通常使用此种获取令牌的方式访问后端认证接口

令牌作用域

  • API认证方式小结
    • API 接口认证本质是获取授权令牌,然后在请求中带上这个令牌对认证接口进行访问的过程
    • 获取令牌的不同实现方式,产生所谓的各式令牌
  • 令牌作用域
    • 对令牌的授权作用域进行限制
    • 理由
      • 不是认证接口的所有返回数据都可以通过该令牌进行访问
      • 不是所有接口都需要通过该令牌进行访问
      • 是否能够获取对应数据或访问对应接口取决于用户的主动勾选
  • 令牌作用域使用实现流程
    • 配置后端应用
      1. 定义API认证的令牌作用域
        • Passport::tokensCan 定义 API 认证的令牌作用域,AuthServiceProvider之boot方法
      2. $routeMiddleware 属性中引入两个中间件
        • 'scopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class,
        • 'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class,
        • scopes 用于检查传入令牌作用域是否包含所有指定中间件参数, 全选
        • scope 用于检查传入令牌作用域是否包含任意指定中间件参数,中间件参数不定项选择
  • 令牌作域特点
    • 本质上是用路由中间件参数标记,认证时会检查令牌上的作用域是否与中间件上指定的标记域相符
    • 与用户数据关联区分标志,使用$user->tokenCan('all-user-info')形式
 类似资料: