goLang-jwt-auth-example

这是用 goLang 实现 jwt auth 的一个例子。「This is an example implementation of jwt auth with goLang」

  • 所有者: adam-hanna/goLang-jwt-auth-example
  • 平台: Linux, Mac, Windows
  • 許可證: MIT License
  • 分類:
  • 主題:
  • 喜歡:
    0
      比較:

Github星跟蹤圖

goLang-jwt-auth-example

这是一个用 goLang 实现 jwt auth 的例子。请注意,我不是这个领域的专家,创建这个资源库更多的是为了学习经验,而不是其他。我希望能从这个经验中学习到很多东西,并分享我的工作,以便你也能学习。

另外,这并不是一个关于如何构建网络应用程序或如何映射和处理授权/非授权路由等的例子。

顺便说一下,我使用的是 goDep

目标

了解这个授权架构的目标是很重要的。这当然不是一个适用于所有用例的设计。请阅读并理解下面的目标,并对你自己的工作流程进行修改以适应你的具体需求。

  1. 保护非关键的 api(例如,不用于金融、医疗、政府等服务)。
  2. 无状态
  3. 用户会话
  4. XSS 保护
  5. CSRF 保护
  6. Web(但可以很容易地修改为用于移动/其他。例如,对于本地移动,不要使用cookie,而是为你的平台使用适当的、安全的存储方法)。

基础知识

这个认证系统的设计是基于以下三个主要部分:

  1. 短暂的(几分钟)JWT 认证令牌
  2. 较长寿命(小时/天)的 JWT 刷新令牌
  3. CSRF 秘密字符串

一旦用户提供了有效的登录凭证,他们会被送回上面列出的三个项目。

1. 短暂的(几分钟)JWT Auth Token

短暂的 jwt auth 令牌允许用户对受保护的 api 端点进行无状态请求,并存在于客户端的 http only cookie 中。它有一个以分钟为单位的过期时间,并将由寿命较长的刷新令牌来刷新。这个令牌包含以下要求。

  • sub [uuid]:请求该请求的主体(用户)。
  • exp [timestamp]:令牌过期的日期/时间(我在这个例子中使用15分钟。 根据你的情况进行调整
  • role [字符串]: "管理员 "或 "用户 "中的一个
  • csrf [字符串]: 一个随机的字符串,用于防止csrf攻击

2. 寿命较长的(小时/天)JWT 刷新令牌

这种寿命较长的令牌将被用来更新认证令牌。这些令牌也将存在于客户端的 http only cookies 中。这些令牌有 72 小时的过期时间,每次刷新认证令牌时都会更新。如果客户试图使用一个过期的刷新令牌,他们将被重新引导到一个登录页面。
这些刷新令牌包含一个可以由授权客户撤销的ID。

该刷新令牌的主张包括:

  • jti [uuid]:一个唯一的字符串,用于识别这个令牌
  • sub [uuid]:请求这个要求的主体(userId)。
  • exp [timestamp]:令牌过期的日期/时间(我在这个例子中使用 72 小时。 根据你的情况进行调整

3. CSRF 秘密字符串

一个 CSRF 秘密字符串将提供给每个客户,并与认证令牌中的 CSRF 秘密相同,而且每次刷新认证令牌时都会改变。这些秘密将存在于 "X-CSRF-Token" 响应头中。这些秘密将与 auth 和刷新令牌一起在每个 api 请求中发送。它们将作为一个隐藏的表单值或在请求头中被发送到服务器。这个秘密将与认证令牌中提供的秘密进行检查,以防止 CSRF 攻击。

认证流程

登录

  1. 用户提供一个用户名和密码
  2. 密码在发送到服务器之前在客户端进行SHA256哈希处理(永远不要简单地依赖https并在网上发送纯文本密码!)。
  3. SHA256密码哈希值被加密并与数据库进行核对
  4. 如果发现匹配,将创建一个认证令牌、刷新令牌和CSRF秘密,并发送回客户端。刷新令牌的JTI被存储在数据库中。
    • 认证令牌和刷新令牌只保存在http cookies中。
    • CSRF秘密在响应头中发送,密钥为 "X-CSRF-Token"。

受限制的API请求

  1. 客户端将CSRF令牌添加到请求头中,密钥为 "X-CSRF-Token"(也可以作为一个隐藏的表单值发送
  2. 对auth令牌进行检查。
    1. 首先,请求头中的csrf秘密与auth jwt中的秘密相匹配
    2. 其次,检查令牌的过期时间。
      1. 如果没有过期,请求被允许
      2. 如果过期,则从刷新令牌中发出一个新的 auth 令牌。检查刷新令牌的有效期,并根据数据库检查JTI。如果这两项检查都通过,就会生成一个新的授权令牌。如果任何一项检查失败,请求就会失败,用户被要求重新登录。
  3. 最后,如果成功,就会生成一个新的csrf秘密,并存储在新创建的auth token中。同时,刷新令牌的过期时间也被重置。
  4. 如上所述,认证令牌、刷新令牌和csrf秘密被送回给客户端。

签出

  1. 签出是一个受限制的路径,所以客户端必须提供一个认证令牌、刷新令牌和csrf秘密。它们被检查,如上所述。
  2. 刷新令牌JTI会从我们数据库中的有效JTI白名单中删除。
  3. 客户端的认证和刷新令牌被取消(它们的值被设置为"")。



主要指標

概覽
名稱與所有者adam-hanna/goLang-jwt-auth-example
主編程語言Go
編程語言Go (語言數: 1)
平台Linux, Mac, Windows
許可證MIT License
所有者活动
創建於2016-06-21 23:19:03
推送於2019-09-06 02:08:03
最后一次提交2016-07-10 20:46:37
發布數3
最新版本名稱v0.0.3 (發布於 2016-07-10 20:46:39)
第一版名稱v0.0.1 (發布於 2016-06-26 16:06:31)
用户参与
星數105
關注者數6
派生數21
提交數9
已啟用問題?
問題數2
打開的問題數2
拉請求數0
打開的拉請求數1
關閉的拉請求數0
项目设置
已啟用Wiki?
已存檔?
是復刻?
已鎖定?
是鏡像?
是私有?

goLang-jwt-auth-example

This is an example implementation of jwt auth with goLang. Please note that I am not an expert in this field and am creating this repository more for a learning experience than anything else. I hope to learn a lot from this experience and am sharing my work so that you might learn, too.

Also, this isn't an exmaple of how to structure a web app or how to map and handle authorized / un-authorized routes, etc.

FYI - I'm using goDep

Goals

It is important to understand the objective of this auth architecture. It certainly is not an applicable design for all use cases. Please read and understand the goals, below, and make changes to your own workflow to suit your specific needs.

  1. Protection of non-critical api's (e.g. not meant for financial, healthcare, gov't, etc. services)
  2. Stateless
  3. User sessions
  4. XSS protection
  5. CSRF protection
  6. Web (but could be easily modified for use in mobile / other. i.e. for native mobile don't use cookies but rather the proper, secure storage methods for your platform)

Basics

The design of this auth system is based around the three major components, listed below.

  1. Short-lived (minutes) JWT Auth Token
  2. Longer-lived (hours / days) JWT Refresh Token
  3. CSRF secret string

Once a user provides valid login credentials, they are sent back the three items listed above.

1. Short-lived (minutes) JWT Auth Token

The short-lived jwt auth token allows the user to make stateless requests to protected api endpoints and lives in an http only cookie on the client. It has an expiration time in minutes and will be refreshed by the longer-lived refresh token. This token contains the following claims:

  • sub [uuid]: the subject (user) who has requested this claim.
  • exp [timestamp]: the date/time the token expires (I'm using 15 minutes in this example. Adjust as you see fit)
  • role [string]: One of "admin" or "user"
  • csrf [string]: A random string to be used to protect against csrf attacks

2. Longer-lived (hours/days) JWT Refresh Token

This longer-lived token will be used to update the auth tokens. These tokens will also live in http only cookies on the client. These tokens have a 72 hour expiration time which will be updated each time an auth token is refreshed. If a client tries to use an expired refresh token, they will be re-directed to a login page.

These refresh tokens contain an id which can be revoked by an authorized client.

The claims of this refresh token include:

  • jti [uuid]: a unique string to identify this token
  • sub [uuid]: the subject (userId) who has requested this claim.
  • exp [timestamp]: the date/time the token expires (I'm using 72 hours in this example. Adjust as you see fit)

3. CSRF Secret String

A CSRF secret string will be provided to each client and will be identical the CSRF secret in the auth token and will change each time an auth token is refreshed. These secrets will live in an "X-CSRF-Token" response header. These secrets will be sent along with the auth and refresh tokens on each api request. They will be sent to the server either as a hidden form value or in the request header. This secret will be checked against the secret provided in the auth token in order to prevent CSRF attacks.

Auth Flow

Sign In

  1. User provides a username and password
  2. Password is SHA256 hashed on the client before being sent to the server (never simply rely on https and send plaintext passwords over the wire!!)
  3. SHA256 password hash is bcrypted and checked against the database
  4. If a match is found, an auth token, refresh token and CSRF secret is created and sent back to the client. The refresh token's JTI is stored in the db.
    • The auth token and refresh tokens are kept in http only cookies
    • The CSRF secret is sent in the response header, with a key of "X-CSRF-Token"

Restricted API request

  1. Client adds the CSRF token to the request header with the key "X-CSRF-Token" (can also be sent as a hidden form value)
  2. The auth token is checked:
    • First, the csrf secret from the request header is matched to the secret in the auth jwt
    • Second, the token expiration time is checked:
      • If not expired, the request is allowed
      • If expired, a new auth token is issued from the refresh token. The refresh token expiration is checked, and the JTI checked against the db. If both checks pass, a new auth token is generated. If either check fails, the request fails and the user is asked to log back in.
  3. Finally, if successful, a new csrf secret is generated and stored in the newly created auth token. Also, the refresh token expiration time is reset.
  4. The auth token, refresh token and csrf secret are sent back to the client as described, above.

Sign out

  1. Signout is a restricted route, so the client must provide an auth token, refresh token and csrf secret. They are checked as described, above.
  2. The refresh token JTI is removed from the whitelisted list of valid JTI's in our db
  3. The client's auth and refresh tokens are nullified (their values are set to "")