歡迎光臨
每天分享高質量文章

無密碼驗證:伺服器 | Linux 中國

無密碼驗證可以讓你只輸入一個 email 而無需輸入密碼即可登入系統。這是一種比傳統的電子郵件/密碼驗證方式登入更安全的方法。
— Nicolás Parada


致謝
編譯自 | https://nicolasparada.netlify.com/posts/passwordless-auth-server/ 
 作者 | Nicolás Parada
 譯者 | qhwdw ? ? ? ? ? 共計翻譯:117 篇 貢獻時間:212 天

無密碼驗證可以讓你只輸入一個 email 而無需輸入密碼即可登入系統。這是一種比傳統的電子郵件/密碼驗證方式登入更安全的方法。

下麵我將為你展示,如何在 Go[1] 中實現一個 HTTP API 去提供這種服務。

流程

◈ 使用者輸入他的電子郵件地址。
◈ 伺服器建立一個臨時的一次性使用的程式碼(就像一個臨時密碼一樣)關聯到使用者,然後給使用者郵箱中傳送一個“魔法連結”。
◈ 使用者點選魔法連結。
◈ 伺服器提取魔法連結中的程式碼,獲取關聯的使用者,並且使用一個新的 JWT 重定向到客戶端。
◈ 在每次有新請求時,客戶端使用 JWT 去驗證使用者。

必需條件

◈ 資料庫:我們為這個服務使用了一個叫 CockroachDB[2] 的 SQL 資料庫。它非常像 postgres,但它是用 Go 寫的。
◈ SMTP 伺服器:我們將使用一個第三方的郵件伺服器去傳送郵件。開發的時我們使用 mailtrap[3]。Mailtrap 傳送所有的郵件到它的收件箱,因此,你在測試時不需要建立多個假郵件帳戶。

從 Go 的主頁[4] 上安裝它,然後使用 go version(1.10.1 atm)命令去檢查它能否正常工作。

從 CockroachDB 的主頁[5] 上下載它,展開它並新增到你的 PATH 變數中。使用 cockroach version(2.0 atm)命令檢查它能否正常工作。

資料庫樣式

現在,我們在 GOPATH 目錄下為這個專案建立一個目錄,然後使用 cockroach start 啟動一個新的 CockroachDB 節點:

  1. cockroach start --insecure --host 127.0.0.1

它會輸出一些內容,找到 SQL 地址行,它將顯示像 postgresql://root@127.0.0.1:26257?sslmode=disable 這樣的內容。稍後我們將使用它去連線到資料庫。

使用如下的內容去建立一個 schema.sql 檔案。

  1. DROP DATABASE IF EXISTS passwordless_demo CASCADE;

  2. CREATE DATABASE IF NOT EXISTS passwordless_demo;

  3. SET DATABASE = passwordless_demo;

  4. CREATE TABLE IF NOT EXISTS users (

  5.    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

  6.    email STRING UNIQUE,

  7.    username STRING UNIQUE

  8. );

  9. CREATE TABLE IF NOT EXISTS verification_codes (

  10.    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

  11.    user_id UUID NOT NULL REFERENCES users ON DELETE CASCADE,

  12.    created_at TIMESTAMPTZ NOT NULL DEFAULT now()

  13. );

  14. INSERT INTO users (email, username) VALUES

  15.    ('john@passwordless.local', 'john_doe');

這個指令碼建立了一個名為 passwordless_demo 的資料庫、兩個名為 users 和 verification_codes 的表,以及為了稍後測試而插入的一些假使用者。每個驗證程式碼都與使用者關聯並儲存建立時間,以用於去檢查驗證程式碼是否過期。

在另外的終端中使用 cockroach sql 命令去執行這個指令碼:

  1. cat schema.sql | cockroach sql --insecure

環境配置

需要配置兩個環境變數:SMTP_USERNAME 和 SMTP_PASSWORD,你可以從你的 mailtrap 帳戶中獲得它們。將在我們的程式中用到它們。

Go 依賴

我們需要下列的 Go 包:

◈ github.com/lib/pq[6]:它是 CockroachDB 使用的 postgres 驅動
◈ github.com/matryer/way[7]: 路由器
◈ github.com/dgrijalva/jwt-go[8]: JWT 實現
  1. go get -u github.com/lib/pq

  2. go get -u github.com/matryer/way

  3. go get -u github.com/dgrijalva/jwt-go

程式碼

初始化函式

建立 main.go 並且透過 init 函式裡的環境變數中取得一些配置來啟動。

  1. var config struct {

  2.    port        int

  3.    appURL      *url.URL

  4.    databaseURL string

  5.    jwtKey      []byte

  6.    smtpAddr    string

  7.    smtpAuth    smtp.Auth

  8. }

  9. func init() {

  10.    config.port, _ = strconv.Atoi(env("PORT", "80"))

  11.    config.appURL, _ = url.Parse(env("APP_URL", "http://localhost:"+strconv.Itoa(config.port)+"/"))

  12.    config.databaseURL = env("DATABASE_URL", "postgresql://root@127.0.0.1:26257/passwordless_demo?sslmode=disable")

  13.    config.jwtKey = []byte(env("JWT_KEY", "super-duper-secret-key"))

  14.    smtpHost := env("SMTP_HOST", "smtp.mailtrap.io")

  15.    config.smtpAddr = net.JoinHostPort(smtpHost, env("SMTP_PORT", "25"))

  16.    smtpUsername, ok := os.LookupEnv("SMTP_USERNAME")

  17.    if !ok {

  18.        log.Fatalln("could not find SMTP_USERNAME on environment variables")

  19.    }

  20.    smtpPassword, ok := os.LookupEnv("SMTP_PASSWORD")

  21.    if !ok {

  22.        log.Fatalln("could not find SMTP_PASSWORD on environment variables")

  23.    }

  24.    config.smtpAuth = smtp.PlainAuth("", smtpUsername, smtpPassword, smtpHost)

  25. }

  26. func env(key, fallbackValue string) string {

  27.    v, ok := os.LookupEnv(key)

  28.    if !ok {

  29.        return fallbackValue

  30.    }

  31.    return v

  32. }

◈ appURL 將去構建我們的 “魔法連結”。
◈ port 將要啟動的 HTTP 伺服器。
◈ databaseURL 是 CockroachDB 地址,我新增 /passwordless_demo 前面的資料庫地址去表示資料庫名字。
◈ jwtKey 用於簽名 JWT。
◈ smtpAddr 是 SMTP_HOST + SMTP_PORT 的聯合;我們將使用它去傳送郵件。
◈ smtpUsername 和 smtpPassword 是兩個必需的變數。
◈ smtpAuth 也是用於傳送郵件。

env 函式允許我們去獲得環境變數,不存在時傳回一個回退值。

主函式

  1. var db *sql.DB

  2. func main() {

  3.    var err error

  4.    if db, err = sql.Open("postgres", config.databaseURL); err != nil {

  5.        log.Fatalf("could not open database connection: %v\n", err)

  6.    }

  7.    defer db.Close()

  8.    if err = db.Ping(); err != nil {

  9.        log.Fatalf("could not ping to database: %v\n", err)

  10.    }

  11.    router := way.NewRouter()

  12.    router.HandleFunc("POST", "/api/users", jsonRequired(createUser))

  13.    router.HandleFunc("POST", "/api/passwordless/start", jsonRequired(passwordlessStart))

  14.    router.HandleFunc("GET", "/api/passwordless/verify_redirect", passwordlessVerifyRedirect)

  15.    router.Handle("GET", "/api/auth_user", authRequired(getAuthUser))

  16.    addr := fmt.Sprintf(":%d", config.port)

  17.    log.Printf("starting server at %s \n", config.appURL)

  18.    log.Fatalf("could not start server: %v\n", http.ListenAndServe(addr, router))

  19. }

首先,開啟資料庫連線。記得要載入驅動。

  1. import (

  2.    _ "github.com/lib/pq"

  3. )

然後,我們建立路由器並定義一些端點。對於無密碼流程來說,我們使用兩個端點:/api/passwordless/start 傳送魔法連結,和 /api/passwordless/verify_redirect 用 JWT 響應。

最後,我們啟動伺服器。

你可以建立空處理程式和中介軟體去測試伺服器啟動。

  1. func createUser(w http.ResponseWriter, r *http.Request) {

  2.    http.Error(w, http.StatusText(http.StatusNotImplemented), http.StatusNotImplemented)

  3. }

  4. func passwordlessStart(w http.ResponseWriter, r *http.Request) {

  5.    http.Error(w, http.StatusText(http.StatusNotImplemented), http.StatusNotImplemented)

  6. }

  7. func passwordlessVerifyRedirect(w http.ResponseWriter, r *http.Request) {

  8.    http.Error(w, http.StatusText(http.StatusNotImplemented), http.StatusNotImplemented)

  9. }

  10. func getAuthUser(w http.ResponseWriter, r *http.Request) {

  11.    http.Error(w, http.StatusText(http.StatusNotImplemented), http.StatusNotImplemented)

  12. }

  13. func jsonRequired(next http.HandlerFunc) http.HandlerFunc {

  14.    return func(w http.ResponseWriter, r *http.Request) {

  15.        next(w, r)

  16.    }

  17. }

  18. func authRequired(next http.HandlerFunc) http.HandlerFunc {

  19.    return func(w http.ResponseWriter, r *http.Request) {

  20.        next(w, r)

  21.    }

  22. }

接下來:

  1. go build

  2. ./passwordless-demo

我們在目錄中有了一個 “passwordless-demo”,但是你的目錄中可能與示例不一樣,go build 將建立一個同名的可執行檔案。如果你沒有關閉前面的 cockroach 節點,並且你正確配置了 SMTP_USERNAME 和 SMTP_PASSWORD 變數,你將看到命令 starting server at http://localhost/ 沒有錯誤輸出。

請求 JSON 的中介軟體

端點需要從請求體中解碼 JSON,因此要確保請求是 application/json 型別。因為它是一個通用的東西,我將它解耦到中介軟體。

  1. func jsonRequired(next http.HandlerFunc) http.HandlerFunc {

  2.    return func(w http.ResponseWriter, r *http.Request) {

  3.        ct := r.Header.Get("Content-Type")

  4.        isJSON := strings.HasPrefix(ct, "application/json")

  5.        if !isJSON {

  6.            respondJSON(w, "JSON body required", http.StatusUnsupportedMediaType)

  7.            return

  8.        }

  9.        next(w, r)

  10.    }

  11. }

實現很容易。首先它從請求頭中獲得內容的型別,然後檢查它是否是以 “application/json” 開始,如果不是則以 415 Unsupported Media Type 提前傳回。

響應 JSON 的函式

以 JSON 響應是非常通用的做法,因此我把它提取到函式中。

  1. func respondJSON(w http.ResponseWriter, payload interface{}, code int) {

  2.    switch value := payload.(type) {

  3.    case string:

  4.        payload = map[string]string{"message": value}

  5.    case int:

  6.        payload = map[string]int{"value": value}

  7.    case bool:

  8.        payload = map[string]bool{"result": value}

  9.    }

  10.    b, err := json.Marshal(payload)

  11.    if err != nil {

  12.        respondInternalError(w, fmt.Errorf("could not marshal response payload: %v", err))

  13.        return

  14.    }

  15.    w.Header().Set("Content-Type", "application/json; charset=utf-8")

  16.    w.WriteHeader(code)

  17.    w.Write(b)

  18. }

首先,對原始型別做一個型別判斷,並將它們封裝到一個 map。然後將它們編組到 JSON,設定響應內容型別和狀態碼,並寫 JSON。如果 JSON 編組失敗,則響應一個內部錯誤。

響應內部錯誤的函式

respondInternalError 是一個響應 500 Internal Server Error 的函式,但是也同時將錯誤輸出到控制檯。

  1. func respondInternalError(w http.ResponseWriter, err error) {

  2.    log.Println(err)

  3.    respondJSON(w,

  4.        http.StatusText(http.StatusInternalServerError),

  5.        http.StatusInternalServerError)

  6. }

建立使用者的處理程式

下麵開始編寫 createUser 處理程式,因為它非常容易並且是 REST 式的。

  1. type User struct {

  2.    ID       string `json:"id"`

  3.    Email    string `json:"email"`

  4.    Username string `json:"username"`

  5. }

User 型別和 users 表相似。

  1. var (

  2.    rxEmail = regexp.MustCompile("^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$")

  3.    rxUsername = regexp.MustCompile("^[a-zA-Z][\\w|-]{1,17}$")

  4. )

這些正則運算式是分別用於去驗證電子郵件和使用者名稱的。這些都很簡單,可以根據你的需要隨意去適配。

現在,在 createUser 函式內部,我們將開始解碼請求體。

  1. var user User

  2. if err := json.NewDecoder(r.Body).Decode(&user); err != nil {

  3.    respondJSON(w, err.Error(), http.StatusBadRequest)

  4.    return

  5. }

  6. defer r.Body.Close()

我們將使用請求體去建立一個 JSON 解碼器來解碼出一個使用者指標。如果發生錯誤則傳回一個 400 Bad Request。不要忘記關閉請求體讀取器。

  1. errs := make(map[string]string)

  2. if user.Email == "" {

  3.    errs["email"] = "Email required"

  4. } else if !rxEmail.MatchString(user.Email) {

  5.    errs["email"] = "Invalid email"

  6. }

  7. if user.Username == "" {

  8.    errs["username"] = "Username required"

  9. } else if !rxUsername.MatchString(user.Username) {

  10.    errs["username"] = "Invalid username"

  11. }

  12. if len(errs) != 0 {

  13.    respondJSON(w, errs, http.StatusUnprocessableEntity)

  14.    return

  15. }

這是我如何做驗證;一個簡單的 map 並檢查如果 len(errs) != 0,則使用 422 Unprocessable Entity 去傳回。

  1. err := db.QueryRowContext(r.Context(), `

  2.    INSERT INTO users (email, username) VALUES ($1, $2)

  3.    RETURNING id

  4. `, user.Email, user.Username).Scan(&user.ID)

  5. if errPq, ok := err.(*pq.Error); ok && errPq.Code.Name() == "unique_violation" {

  6.    if strings.Contains(errPq.Error(), "email") {

  7.        errs["email"] = "Email taken"

  8.    } else {

  9.        errs["username"] = "Username taken"

  10.    }

  11.    respondJSON(w, errs, http.StatusForbidden)

  12.    return

  13. } else if err != nil {

  14.    respondInternalError(w, fmt.Errorf("could not insert user: %v", err))

  15.    return

  16. }

這個 SQL 查詢使用一個給定的 email 和使用者名稱去插入一個新使用者,並傳回自動生成的 id,每個 $ 將被接下來傳遞給 QueryRowContext 的引數替換掉。

因為 users 表在 email 和 username 欄位上有唯一性約束,因此我將檢查 “unique_violation” 錯誤並傳回 403 Forbidden 或者傳回一個內部錯誤。

  1. respondJSON(w, user, http.StatusCreated)

最後使用建立的使用者去響應。

無密碼驗證開始部分的處理程式

  1. type PasswordlessStartRequest struct {

  2.    Email       string `json:"email"`

  3.    RedirectURI string `json:"redirectUri"`

  4. }

這個結構體含有 passwordlessStart 的請求體:希望去登入的使用者 email、來自客戶端的重定向 URI(這個應用中將使用我們的 API)如:https://frontend.app/callback

  1. var magicLinkTmpl = template.Must(template.ParseFiles("templates/magic-link.html"))

我們將使用 golang 模板引擎去構建郵件,因此需要你在 templates 目錄中,用如下的內容建立一個 magic-link.html 檔案:

  1. lang="en">

  2.     charset="utf-8">

  3.     name="viewport" content="width=device-width, initial-scale=1.0">

  4.    </span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">Magic Link</span><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"/></code></p></li></ol></pre> </section> <li> <p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"/></code></p> </li> <li> <p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"/></code></p> </li> <li> <p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    Click </span><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"><a><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="atn" style="word-wrap: break-word;color: rgb(189, 183, 107);">href</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="atv" style="word-wrap: break-word;color: rgb(101, 176, 66);">"{{ .MagicLink }}"</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="atn" style="word-wrap: break-word;color: rgb(189, 183, 107);">target</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="atv" style="word-wrap: break-word;color: rgb(101, 176, 66);">"_blank"</span><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);">></span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">here</span><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"/></a></span></code></p> </li> <p><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> to login.</span></p> <li> <p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"><br /></span></code></p> </li> <li> <p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"><em/></span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">This link expires in 15 minutes and can only be used once.</span><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"/></code></p> </li> <li> <p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"/></code></p> </li> <li> <p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="tag" style="word-wrap: break-word;color: rgb(137, 189, 255);"/></code></p> </li> <li> <p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p> </li> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">這個模板是給使用者傳送魔法連結郵件用的。你可以根據你的需要去隨意調整它。</p> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">現在, 進入 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">passwordlessStart</code> 函式內部:</p> <pre class="prettyprint linenums prettyprinted" style="word-wrap: break-word;background-color: rgb(22, 27, 32);background-image: none;box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px;text-shadow: rgb(0, 0, 0) 0px 1px 1px;border-radius: 6px;color: rgb(184, 255, 184);margin: 10px;padding: 1em 1em 1em 0px;white-space: pre-wrap;border-width: 1px;border-style: solid;border-color: rgb(0, 0, 0);line-height: 1.2em;letter-spacing: 0px !important;"><ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;"><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> input </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">PasswordlessStartRequest</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> json</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">NewDecoder</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Body</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">).</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Decode</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(&</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">input</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">);</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Error</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusBadRequest</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">defer r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Body</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Close</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li></ol></pre> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">首先,我們像前面一樣解碼請求體。</p> <pre class="prettyprint linenums prettyprinted" style="word-wrap: break-word;background-color: rgb(22, 27, 32);background-image: none;box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px;text-shadow: rgb(0, 0, 0) 0px 1px 1px;border-radius: 6px;color: rgb(184, 255, 184);margin: 10px;padding: 1em 1em 1em 0px;white-space: pre-wrap;border-width: 1px;border-style: solid;border-color: rgb(0, 0, 0);line-height: 1.2em;letter-spacing: 0px !important;"><ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;"><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">errs </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">make</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">map</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> input</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Email</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">==</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">""</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"email"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Email required"</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">else</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">rxEmail</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">MatchString</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">input</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Email</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"email"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Invalid email"</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> input</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">RedirectURI</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">==</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">""</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"redirectUri"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Redirect URI required"</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">else</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> u</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> url</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Parse</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">input</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">RedirectURI</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">);</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">||</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">u</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">IsAbs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"redirectUri"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Invalid redirect URI"</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> len</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="lit" style="word-wrap: break-word;color: rgb(51, 135, 204);">0</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusUnprocessableEntity</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li></ol></pre> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">我們使用 golang 的 URL 解析器去驗證重定向 URI,檢查那個 URI 是否為絕對地址。</p> <pre class="prettyprint linenums prettyprinted" style="word-wrap: break-word;background-color: rgb(22, 27, 32);background-image: none;box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px;text-shadow: rgb(0, 0, 0) 0px 1px 1px;border-radius: 6px;color: rgb(184, 255, 184);margin: 10px;padding: 1em 1em 1em 0px;white-space: pre-wrap;border-width: 1px;border-style: solid;border-color: rgb(0, 0, 0);line-height: 1.2em;letter-spacing: 0px !important;"><ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;"><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> verificationCode string</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> db</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">QueryRowContext</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Context</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">`</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">    INSERT INTO verification_codes (user_id) VALUES</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">        ((SELECT id FROM users WHERE email = $1))</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">    RETURNING id</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">`</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> input</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Email</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">).</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Scan</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(&</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">verificationCode</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> errPq</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> ok </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.(*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">pq</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Error</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">);</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> ok </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">&&</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> errPq</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Code</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Name</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">==</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"not_null_violation"</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"No user found with that email"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusNotFound</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">else</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondInternalError</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fmt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Errorf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not insert verification code: %v"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li></ol></pre> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">這個 SQL 查詢將插入一個驗證程式碼,這個程式碼透過給定的 email 關聯到使用者,並且傳回一個自動生成的 id。因為有可能會出現使用者不存在的情況,那樣的話子查詢可能解析為 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">NULL</code>,這將導致在 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">user_id</code> 欄位上因違反 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">NOT NULL</code> 約束而導致失敗,因此需要對這種情況進行檢查,如果使用者不存在,則傳回 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">404 Not Found</code> 或者一個內部錯誤。</p> <pre class="prettyprint linenums prettyprinted" style="word-wrap: break-word;background-color: rgb(22, 27, 32);background-image: none;box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px;text-shadow: rgb(0, 0, 0) 0px 1px 1px;border-radius: 6px;color: rgb(184, 255, 184);margin: 10px;padding: 1em 1em 1em 0px;white-space: pre-wrap;border-width: 1px;border-style: solid;border-color: rgb(0, 0, 0);line-height: 1.2em;letter-spacing: 0px !important;"><ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;"><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">q </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">make</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">url</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Values</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">q</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Set</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"verification_code"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> verificationCode</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">q</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Set</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"redirect_uri"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> input</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">RedirectURI</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">magicLink </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">appURL</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">magicLink</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Path</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"/api/passwordless/verify_redirect"</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">magicLink</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">RawQuery</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> q</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Encode</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li></ol></pre> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">現在,構建魔法連結並設定查詢字串中的 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">verification_code</code> 和 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">redirect_uri</code> 的值。如:<code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">http://localhost/api/passwordless/verify_redirect?verification_code=some_code&redirect;_uri=https://frontend.app/callback</code>。</p> <pre class="prettyprint linenums prettyprinted" style="word-wrap: break-word;background-color: rgb(22, 27, 32);background-image: none;box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px;text-shadow: rgb(0, 0, 0) 0px 1px 1px;border-radius: 6px;color: rgb(184, 255, 184);margin: 10px;padding: 1em 1em 1em 0px;white-space: pre-wrap;border-width: 1px;border-style: solid;border-color: rgb(0, 0, 0);line-height: 1.2em;letter-spacing: 0px !important;"><ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;"><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> body bytes</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Buffer</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">data </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> map</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"MagicLink"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> magicLink</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">String</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> magicLinkTmpl</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Execute</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(&</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">body</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> data</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">);</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondInternalError</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fmt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Errorf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not execute magic link template: %v"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li></ol></pre> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">我們將得到的魔法連結模板的內容儲存到緩衝區中。如果發生錯誤則傳回一個內部錯誤。</p> <pre class="prettyprint linenums prettyprinted" style="word-wrap: break-word;background-color: rgb(22, 27, 32);background-image: none;box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px;text-shadow: rgb(0, 0, 0) 0px 1px 1px;border-radius: 6px;color: rgb(184, 255, 184);margin: 10px;padding: 1em 1em 1em 0px;white-space: pre-wrap;border-width: 1px;border-style: solid;border-color: rgb(0, 0, 0);line-height: 1.2em;letter-spacing: 0px !important;"><ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;"><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">to </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> mail</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Address</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Address</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> input</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Email</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> sendMail</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">to</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Magic Link"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> body</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">String</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">());</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondInternalError</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fmt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Errorf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not mail magic link: %v"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li></ol></pre> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">現在來寫給使用者發郵件的 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">sendMail</code> 函式。如果發生錯誤則傳回一個內部錯誤。</p> <pre class="prettyprint linenums prettyprinted" style="word-wrap: break-word;background-color: rgb(22, 27, 32);background-image: none;box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px;text-shadow: rgb(0, 0, 0) 0px 1px 1px;border-radius: 6px;color: rgb(184, 255, 184);margin: 10px;padding: 1em 1em 1em 0px;white-space: pre-wrap;border-width: 1px;border-style: solid;border-color: rgb(0, 0, 0);line-height: 1.2em;letter-spacing: 0px !important;"><ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;"><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">WriteHeader</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusNoContent</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li></ol></pre> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">最後,設定響應狀態碼為 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">204 No Content</code>。對於成功的狀態碼,客戶端不需要很多資料。</p> <p class="h4" style="word-wrap: break-word;margin-top: 8px;margin-right: 10px;margin-bottom: 8px;padding: 6px 15px;line-height: 1.6em;background-image: linear-gradient(to right bottom, rgb(0, 188, 212), rgb(63, 81, 181));background-color: rgb(63, 81, 181);color: rgb(255, 255, 255);font-size: 1.2em;border-left: 5px solid rgb(51, 51, 51);text-shadow: rgb(102, 102, 102) 1px 1px 1px;box-shadow: rgb(102, 102, 102) 1px 1px 2px;">傳送郵件函式</p> <pre class="prettyprint linenums prettyprinted" style="word-wrap: break-word;background-color: rgb(22, 27, 32);background-image: none;box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px;text-shadow: rgb(0, 0, 0) 0px 1px 1px;border-radius: 6px;color: rgb(184, 255, 184);margin: 10px;padding: 1em 1em 1em 0px;white-space: pre-wrap;border-width: 1px;border-style: solid;border-color: rgb(0, 0, 0);line-height: 1.2em;letter-spacing: 0px !important;"><ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;"><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func sendMail</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">to mail</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Address</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> subject</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> body string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> error </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">from</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> mail</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Address</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Name</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Passwordless Demo"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Address</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"noreply@"</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">+</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">appURL</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Host</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    essay-headers </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> map</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"From"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">         </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">from</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">String</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(),</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"To"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">           to</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">String</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(),</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Subject"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">      subject</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Content-Type"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">`text/html; charset="utf-8"`</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    msg </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">""</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">for</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> k</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> v </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> range essay-headers </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        msg </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">+=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fmt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Sprintf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"%s: %s\r\n"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> k</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> v</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    msg </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">+=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"\r\n"</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    msg </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">+=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> body</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> smtp</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">SendMail</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">smtpAddr</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">smtpAuth</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">from</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Address</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">to</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Address</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">},</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">byte</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">msg</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li></ol></pre> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">這個函式建立一個基本的 HTML 郵件結構體並使用 SMTP 伺服器去傳送它。郵件的內容你可以隨意定製,我喜歡使用比較簡單的內容。</p> <p class="h4" style="word-wrap: break-word;margin-top: 8px;margin-right: 10px;margin-bottom: 8px;padding: 6px 15px;line-height: 1.6em;background-image: linear-gradient(to right bottom, rgb(0, 188, 212), rgb(63, 81, 181));background-color: rgb(63, 81, 181);color: rgb(255, 255, 255);font-size: 1.2em;border-left: 5px solid rgb(51, 51, 51);text-shadow: rgb(102, 102, 102) 1px 1px 1px;box-shadow: rgb(102, 102, 102) 1px 1px 2px;">無密碼驗證重定向的處理程式</p> <pre class="prettyprint linenums prettyprinted" style="word-wrap: break-word;background-color: rgb(22, 27, 32);background-image: none;box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px;text-shadow: rgb(0, 0, 0) 0px 1px 1px;border-radius: 6px;color: rgb(184, 255, 184);margin: 10px;padding: 1em 1em 1em 0px;white-space: pre-wrap;border-width: 1px;border-style: solid;border-color: rgb(0, 0, 0);line-height: 1.2em;letter-spacing: 0px !important;"><ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;"><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> rxUUID </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> regexp</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">MustCompile</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li></ol></pre> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">首先,這個正則運算式去驗證一個 UUID(即驗證程式碼)。</p> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">現在進入 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">passwordlessVerifyRedirect</code> 函式內部:</p> <pre class="prettyprint linenums prettyprinted" style="word-wrap: break-word;background-color: rgb(22, 27, 32);background-image: none;box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px;text-shadow: rgb(0, 0, 0) 0px 1px 1px;border-radius: 6px;color: rgb(184, 255, 184);margin: 10px;padding: 1em 1em 1em 0px;white-space: pre-wrap;border-width: 1px;border-style: solid;border-color: rgb(0, 0, 0);line-height: 1.2em;letter-spacing: 0px !important;"><ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;"><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">q </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">URL</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Query</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">verificationCode </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> q</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Get</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"verification_code"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">redirectURI </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> q</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Get</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"redirect_uri"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li></ol></pre> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;"><code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">/api/passwordless/verify_redirect</code> 是一個 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">GET</code> 端點,以便於我們從查詢字串中讀取資料。</p> <pre class="prettyprint linenums prettyprinted" style="word-wrap: break-word;background-color: rgb(22, 27, 32);background-image: none;box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px;text-shadow: rgb(0, 0, 0) 0px 1px 1px;border-radius: 6px;color: rgb(184, 255, 184);margin: 10px;padding: 1em 1em 1em 0px;white-space: pre-wrap;border-width: 1px;border-style: solid;border-color: rgb(0, 0, 0);line-height: 1.2em;letter-spacing: 0px !important;"><ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;"><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">errs </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">make</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">map</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> verificationCode </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">==</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">""</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"verification_code"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Verification code required"</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">else</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">rxUUID</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">MatchString</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">verificationCode</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"verification_code"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Invalid verification code"</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> callback </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">url</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">URL</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err error</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> redirectURI </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">==</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">""</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"redirect_uri"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Redirect URI required"</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">else</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> callback</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> url</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Parse</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">redirectURI</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">);</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">||</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">callback</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">IsAbs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"redirect_uri"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Invalid redirect URI"</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> len</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="lit" style="word-wrap: break-word;color: rgb(51, 135, 204);">0</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> errs</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusUnprocessableEntity</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li></ol></pre> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">類似的驗證,我們儲存解析後的重定向 URI 到一個 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">callback</code> 變數中。</p> <pre class="prettyprint linenums prettyprinted" style="word-wrap: break-word;background-color: rgb(22, 27, 32);background-image: none;box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px;text-shadow: rgb(0, 0, 0) 0px 1px 1px;border-radius: 6px;color: rgb(184, 255, 184);margin: 10px;padding: 1em 1em 1em 0px;white-space: pre-wrap;border-width: 1px;border-style: solid;border-color: rgb(0, 0, 0);line-height: 1.2em;letter-spacing: 0px !important;"><ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;"><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> userID string</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> db</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">QueryRowContext</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Context</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">`</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">    DELETE FROM verification_codes</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">    WHERE id = $1</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">        AND created_at >= now() - INTERVAL '15m'</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">    RETURNING user_id</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">`</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> verificationCode</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">).</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Scan</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(&</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">userID</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">);</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">==</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> sql</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ErrNoRows</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Link expired or already used"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusBadRequest</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">else</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondInternalError</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fmt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Errorf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not delete verification code: %v"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li></ol></pre> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">這個 SQL 查詢透過給定的 id 去刪除相應的驗證程式碼,並且確保它建立之後時間不超過 15 分鐘,它也傳回關聯的 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">user_id</code>。如果沒有檢索到內容,意味著程式碼不存在或者已過期,我們傳回一個響應資訊,否則就傳回一個內部錯誤。</p> <pre class="prettyprint linenums prettyprinted" style="word-wrap: break-word;background-color: rgb(22, 27, 32);background-image: none;box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px;text-shadow: rgb(0, 0, 0) 0px 1px 1px;border-radius: 6px;color: rgb(184, 255, 184);margin: 10px;padding: 1em 1em 1em 0px;white-space: pre-wrap;border-width: 1px;border-style: solid;border-color: rgb(0, 0, 0);line-height: 1.2em;letter-spacing: 0px !important;"><ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;"><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">expiresAt </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">time</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Now</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">().</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Add</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">time</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Hour</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="lit" style="word-wrap: break-word;color: rgb(51, 135, 204);">24</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="lit" style="word-wrap: break-word;color: rgb(51, 135, 204);">60</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">tokenString</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> jwt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">NewWithClaims</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">jwt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">SigningMethodHS256</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> jwt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StandardClaims</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Subject</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">   userID</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ExpiresAt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> expiresAt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Unix</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(),</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}).</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">SignedString</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">jwtKey</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondInternalError</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fmt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Errorf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not create JWT: %v"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li></ol></pre> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">這些是如何去建立 JWT。我們為 JWT 設定一個 60 天的過期值,你也可以設定更短的時間(大約 2 周),並新增一個新端點去掃清令牌,但是不要搞的過於複雜。</p> <pre class="prettyprint linenums prettyprinted" style="word-wrap: break-word;background-color: rgb(22, 27, 32);background-image: none;box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px;text-shadow: rgb(0, 0, 0) 0px 1px 1px;border-radius: 6px;color: rgb(184, 255, 184);margin: 10px;padding: 1em 1em 1em 0px;white-space: pre-wrap;border-width: 1px;border-style: solid;border-color: rgb(0, 0, 0);line-height: 1.2em;letter-spacing: 0px !important;"><ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;"><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">expiresAtB</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> expiresAt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">MarshalText</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondInternalError</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fmt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Errorf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not marshal expiration date: %v"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">f </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">make</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">url</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Values</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">f</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Set</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"jwt"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> tokenString</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">f</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Set</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"expires_at"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">expiresAtB</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">callback</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Fragment</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> f</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Encode</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li></ol></pre> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">我們去規劃重定向;你可使用查詢字串去新增 JWT,但是更常見的是使用一個雜湊片段。如:<code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">https://frontend.app/callback#jwt=token_here&expires;_at=some_date</code>.</p> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">過期日期可以從 JWT 中提取出來,但是這樣做的話,就需要在客戶端上實現一個 JWT 庫來解碼它,因此為了簡化,我將它加到這裡。</p> <pre class="prettyprint linenums prettyprinted" style="word-wrap: break-word;background-color: rgb(22, 27, 32);background-image: none;box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px;text-shadow: rgb(0, 0, 0) 0px 1px 1px;border-radius: 6px;color: rgb(184, 255, 184);margin: 10px;padding: 1em 1em 1em 0px;white-space: pre-wrap;border-width: 1px;border-style: solid;border-color: rgb(0, 0, 0);line-height: 1.2em;letter-spacing: 0px !important;"><ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;"><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Redirect</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> callback</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">String</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusFound</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li></ol></pre> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">最後我們使用一個 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">302 Found</code> 重定向。</p> <hr style="word-wrap: break-word;clear: both;margin-right: 10px;margin-left: 10px;"/> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">無密碼的流程已經完成。現在需要去寫 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">getAuthUser</code> 端點的程式碼了,它用於獲取當前驗證使用者的資訊。你應該還記得,這個端點使用了 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">guard</code> 中介軟體。</p> <p class="h4" style="word-wrap: break-word;margin-top: 8px;margin-right: 10px;margin-bottom: 8px;padding: 6px 15px;line-height: 1.6em;background-image: linear-gradient(to right bottom, rgb(0, 188, 212), rgb(63, 81, 181));background-color: rgb(63, 81, 181);color: rgb(255, 255, 255);font-size: 1.2em;border-left: 5px solid rgb(51, 51, 51);text-shadow: rgb(102, 102, 102) 1px 1px 1px;box-shadow: rgb(102, 102, 102) 1px 1px 2px;">使用 Auth 中介軟體</p> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">在編寫 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">guard</code> 中介軟體之前,我將編寫一個不需要驗證的分支。目的是,如果沒有傳遞 JWT,它將不去驗證使用者。</p> <pre class="prettyprint linenums prettyprinted" style="word-wrap: break-word;background-color: rgb(22, 27, 32);background-image: none;box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px;text-shadow: rgb(0, 0, 0) 0px 1px 1px;border-radius: 6px;color: rgb(184, 255, 184);margin: 10px;padding: 1em 1em 1em 0px;white-space: pre-wrap;border-width: 1px;border-style: solid;border-color: rgb(0, 0, 0);line-height: 1.2em;letter-spacing: 0px !important;"><ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;"><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">type </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ContextKey</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">struct</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Name</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> string</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">var</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> keyAuthUserID </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ContextKey</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"auth_user_id"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func withAuth</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">next</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">HandlerFunc</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">HandlerFunc</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> func</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ResponseWriter</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Request</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        a </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Header</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Get</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Authorization"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        hasToken </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">strings</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">HasPrefix</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">a</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"Bearer "</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">hasToken </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">next</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        tokenString </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> a</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[</span><span class="lit" style="word-wrap: break-word;color: rgb(51, 135, 204);">7</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:]</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        p </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> jwt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Parser</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ValidMethods</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">[]</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">jwt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">SigningMethodHS256</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Name</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        token</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> p</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ParseWithClaims</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            tokenString</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">&</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">jwt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StandardClaims</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{},</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            func </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">jwt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Token</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">interface</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{},</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> error</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> config</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">jwtKey</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">},</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusText</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusUnauthorized</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusUnauthorized</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        claims</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> ok </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> token</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Claims</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.(*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">jwt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StandardClaims</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ok </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">||</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">token</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Valid</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusText</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusUnauthorized</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusUnauthorized</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        ctx </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Context</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        ctx </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> context</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">WithValue</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ctx</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> keyAuthUserID</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> claims</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Subject</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">next</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">WithContext</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ctx</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li></ol></pre> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">JWT 將在每次請求時以 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">Bearer <token_here/></code> 格式包含在 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">Authorization</code> 頭中。因此,如果沒有提供令牌,我們將直接透過,進入接下來的中介軟體。</p> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">我們建立一個解析器來解析令牌。如果解析失敗則傳回 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">401 Unauthorized</code>。</p> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">然後我們從 JWT 中提取出要求的內容,並新增 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">Subject</code>(就是使用者 ID)到需要的地方。</p> <p class="h4" style="word-wrap: break-word;margin-top: 8px;margin-right: 10px;margin-bottom: 8px;padding: 6px 15px;line-height: 1.6em;background-image: linear-gradient(to right bottom, rgb(0, 188, 212), rgb(63, 81, 181));background-color: rgb(63, 81, 181);color: rgb(255, 255, 255);font-size: 1.2em;border-left: 5px solid rgb(51, 51, 51);text-shadow: rgb(102, 102, 102) 1px 1px 1px;box-shadow: rgb(102, 102, 102) 1px 1px 2px;">Guard 中介軟體</p> <pre class="prettyprint linenums prettyprinted" style="word-wrap: break-word;background-color: rgb(22, 27, 32);background-image: none;box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px;text-shadow: rgb(0, 0, 0) 0px 1px 1px;border-radius: 6px;color: rgb(184, 255, 184);margin: 10px;padding: 1em 1em 1em 0px;white-space: pre-wrap;border-width: 1px;border-style: solid;border-color: rgb(0, 0, 0);line-height: 1.2em;letter-spacing: 0px !important;"><ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;"><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func guard</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">next</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">HandlerFunc</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">HandlerFunc</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> withAuth</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ResponseWriter</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">*</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Request</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        _</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> ok </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Context</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">().</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Value</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">keyAuthUserID</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">).(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ok </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusText</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusUnauthorized</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusUnauthorized</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">            </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">        </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">next</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">})</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li></ol></pre> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">現在,<code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">guard</code> 將使用 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">withAuth</code> 並從請求內容中提取出驗證使用者的 ID。如果提取失敗,它將傳回 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">401 Unauthorized</code>,提取成功則繼續下一步。</p> <p class="h4" style="word-wrap: break-word;margin-top: 8px;margin-right: 10px;margin-bottom: 8px;padding: 6px 15px;line-height: 1.6em;background-image: linear-gradient(to right bottom, rgb(0, 188, 212), rgb(63, 81, 181));background-color: rgb(63, 81, 181);color: rgb(255, 255, 255);font-size: 1.2em;border-left: 5px solid rgb(51, 51, 51);text-shadow: rgb(102, 102, 102) 1px 1px 1px;box-shadow: rgb(102, 102, 102) 1px 1px 2px;">獲取 Auth 使用者</p> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">在 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">getAuthUser</code> 處理程式內部:</p> <pre class="prettyprint linenums prettyprinted" style="word-wrap: break-word;background-color: rgb(22, 27, 32);background-image: none;box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px;text-shadow: rgb(0, 0, 0) 0px 1px 1px;border-radius: 6px;color: rgb(184, 255, 184);margin: 10px;padding: 1em 1em 1em 0px;white-space: pre-wrap;border-width: 1px;border-style: solid;border-color: rgb(0, 0, 0);line-height: 1.2em;letter-spacing: 0px !important;"><ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;"><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ctx </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> r</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Context</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">()</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">authUserID </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> ctx</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Value</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">keyAuthUserID</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">).(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">user</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fetchUser</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ctx</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> authUserID</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">==</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> sql</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">ErrNoRows</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusText</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusTeapot</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">),</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusTeapot</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">else</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">if</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">!=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">nil</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    respondInternalError</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> fmt</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Errorf</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">"could not query auth user: %v"</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">))</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">respondJSON</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">w</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> user</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> http</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">StatusOK</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li></ol></pre> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">首先,我們從請求內容中提取驗證使用者的 ID,我們使用這個 ID 去獲取使用者。如果沒有獲取到內容,則傳送一個 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">418 I'm a teapot</code>,或者一個內部錯誤。最後,我們將用這個使用者去響應。</p> <p class="h4" style="word-wrap: break-word;margin-top: 8px;margin-right: 10px;margin-bottom: 8px;padding: 6px 15px;line-height: 1.6em;background-image: linear-gradient(to right bottom, rgb(0, 188, 212), rgb(63, 81, 181));background-color: rgb(63, 81, 181);color: rgb(255, 255, 255);font-size: 1.2em;border-left: 5px solid rgb(51, 51, 51);text-shadow: rgb(102, 102, 102) 1px 1px 1px;box-shadow: rgb(102, 102, 102) 1px 1px 2px;">獲取 User 函式</p> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">下麵你看到的是 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">fetchUser</code> 函式。</p> <pre class="prettyprint linenums prettyprinted" style="word-wrap: break-word;background-color: rgb(22, 27, 32);background-image: none;box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 5px;text-shadow: rgb(0, 0, 0) 0px 1px 1px;border-radius: 6px;color: rgb(184, 255, 184);margin: 10px;padding: 1em 1em 1em 0px;white-space: pre-wrap;border-width: 1px;border-style: solid;border-color: rgb(0, 0, 0);line-height: 1.2em;letter-spacing: 0px !important;"><ol class="linenums list-paddingleft-2" style="margin-left: 2em;margin-right: 2em;"><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">func fetchUser</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ctx context</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Context</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">id</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> string</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">User</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> error</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    user </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">User</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">{</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ID</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">id</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    err </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">:=</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> db</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">QueryRowContext</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">ctx</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">`</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">        SELECT email, username FROM users WHERE id = $1</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="str" style="word-wrap: break-word;color: rgb(101, 176, 66);">    `</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">id</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">).</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Scan</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">(&</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">user</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Email</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> </span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">&</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">user</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">.</span><span class="typ" style="word-wrap: break-word;color: rgb(137, 189, 255);">Username</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">)</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);">    </span><span class="kwd" style="word-wrap: break-word;color: rgb(226, 137, 100);">return</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> user</span><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">,</span><span class="pln" style="word-wrap: break-word;color: rgb(184, 255, 184);"> err</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"><span class="pun" style="word-wrap: break-word;color: rgb(184, 255, 184);">}</span></code></p></li><li><p><code style="word-wrap: break-word;background: none;color: rgb(33, 150, 243);line-height: 1.2em;padding-left: 10px !important;border-radius: 0px !important;margin-top: 1em !important;margin-bottom: 1em !important;border-width: initial !important;border-style: none !important;border-color: initial !important;"/></p></li></ol></pre> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">我將它解耦是因為透過 ID 來獲取使用者是個常做的事。</p> <hr style="word-wrap: break-word;clear: both;margin-right: 10px;margin-left: 10px;"/> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">以上就是全部的程式碼。你可以自己去構建它和測試它。<span style="word-wrap: break-word;color: rgb(77, 138, 216);">這裡</span><span class="sup" style="word-wrap: break-word;font-size: 9px;vertical-align: super;background-color: rgb(102, 102, 102);color: rgb(255, 255, 255);transform: scale(0.75);display: inline-block;padding: 1px;line-height: 1em;">[9]</span> 還有一個 demo 你可以試用一下。</p> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">如果你在 mailtrap 上點選之後出現有關 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">指令碼執行被攔截,因為檔案的框架是沙箱化的,並且沒有設定 'allow-scripts' 許可權</code> 的問題,你可以嘗試右鍵點選 “在新標簽中開啟連結“。這樣做是安全的,因為郵件內容是 <span style="word-wrap: break-word;color: rgb(77, 138, 216);">沙箱化的</span><span class="sup" style="word-wrap: break-word;font-size: 9px;vertical-align: super;background-color: rgb(102, 102, 102);color: rgb(255, 255, 255);transform: scale(0.75);display: inline-block;padding: 1px;line-height: 1em;">[10]</span>。我在 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">localhost</code> 上有時也會出現這個問題,但是我認為你一旦以 <code style="word-wrap: break-word;background: none rgb(238, 238, 238);padding: 2px 4px;border-radius: 4px;margin-right: 4px;margin-left: 4px;color: rgb(33, 150, 243);line-height: 1.2em;">https://</code> 方式部署到伺服器上應該不會出現這個問題了。</p> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">如果有任何問題,請在我的 <span style="word-wrap: break-word;color: rgb(77, 138, 216);">GitHub repo</span><span class="sup" style="word-wrap: break-word;font-size: 9px;vertical-align: super;background-color: rgb(102, 102, 102);color: rgb(255, 255, 255);transform: scale(0.75);display: inline-block;padding: 1px;line-height: 1em;">[11]</span> 留言或者提交 PRs</p> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">以後,我為這個 API 寫了一個客戶端作為這篇文章的<span style="word-wrap: break-word;color: rgb(77, 138, 216);">第二部分</span><span class="sup" style="word-wrap: break-word;font-size: 9px;vertical-align: super;background-color: rgb(102, 102, 102);color: rgb(255, 255, 255);transform: scale(0.75);display: inline-block;padding: 1px;line-height: 1em;">[12]</span>。</p> <hr style="word-wrap: break-word;clear: both;margin-right: 10px;margin-left: 10px;"/> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">via: <span style="word-wrap: break-word;color: rgb(77, 138, 216);">https://nicolasparada.netlify.com/posts/passwordless-auth-server/</span></p> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">作者:<span style="word-wrap: break-word;color: rgb(77, 138, 216);">Nicolás Parada</span><span class="sup" style="word-wrap: break-word;font-size: 9px;vertical-align: super;background-color: rgb(102, 102, 102);color: rgb(255, 255, 255);transform: scale(0.75);display: inline-block;padding: 1px;line-height: 1em;">[14]</span> 譯者:<span style="word-wrap: break-word;color: rgb(77, 138, 216);">qhwdw</span> 校對:<span style="word-wrap: break-word;color: rgb(77, 138, 216);">wxy</span></p> <p style="word-wrap: break-word;margin-top: 1.5em;margin-bottom: 1.5em;line-height: 2em;">本文由 <span style="word-wrap: break-word;color: rgb(77, 138, 216);">LCTT</span> 原創編譯,<span style="word-wrap: break-word;color: rgb(77, 138, 216);">Linux中國</span> 榮譽推出</p> <p></p> <div class="ct_mpda_wrp" id="js_sponsor_ad_area" style="display:none;"/> <div class="reward_area tc reward_area_primary" id="js_preview_reward_author" style="display:none;"> <div class="reward-avatar" id="js_preview_reward_author_avatar" style="display: none;"> <img alt="" id="js_preview_reward_author_head" src=""/> </div> <div class="reward-author" id="js_preview_reward_author_name">譯者:qhwdw</div> <p class="reward_tips" id="js_preview_reward_author_wording" style="display:none;"/> <p> <a class="reward_button" csmlink="CtcF3c" href="http://chuansongme.com/r/CtcF3c" id="js_preview_reward_author_link" rel="nofollow"><span id="js_preview_reward_link_text">贊賞</span></a> </p> </div> <div class="reward_qrcode_area reward_area tc" id="js_preview_reward_qrcode" style="display:none;"> <p class="tips_global">長按二維碼向我轉賬</p> <p class="reward_tips" id="js_preview_reward_ios_wording" style="display:none;"/> <span class="reward_qrcode_img_wrp"><img class="reward_qrcode_img" src="//res.wx.qq.com/mmbizwap/zh_CN/htmledition/images/pic/appmsg/pic_reward_qrcode.2x3534dd.png"/></span></p> <p class="tips_global">受蘋果公司新規定影響,微信 iOS 版的贊賞功能被關閉,可透過二維碼轉賬支援公眾號。</p> </div> <ul class="article_extend_area" id="js_hotspot_area"/> <div class="rich_media_tool" id="js_toobar3"> <a class="media_tool_meta meta_primary" csmlink="DtcF3c" href="http://chuansongme.com/r/DtcF3c" id="js_view_source" rel="nofollow" target="_blank">閱讀原文</a></p> </div> <div class="weui-desktop-popover weui-desktop-popover_pos-up-center weui-desktop-popover_img-text" id="js_pc_weapp_code" style="display: none;"> <div class="weui-desktop-popover__content"> <div class="weui-desktop-popover__desc"> <img id="js_pc_weapp_code_img"/><br /> 微信掃一掃<br />使用小程式<span id="js_pc_weapp_code_des"/> </div> </div> </div> <div id="js_minipro_dialog" style="display:none;"> <div class="weui-mask"/> <div class="weui-dialog"> <div class="weui-dialog__bd">即將開啟"<span id="js_minipro_dialog_name"/>"小程式</div> <div class="weui-dialog__ft"> <a class="weui-dialog__btn weui-dialog__btn_default" href="javascript:void(0);" id="js_minipro_dialog_cancel">取消</a><br /> <a class="weui-dialog__btn weui-dialog__btn_primary" href="javascript:void(0);" id="js_minipro_dialog_ok">開啟</a> </div> </div> </div> </div> </article> <div class="post-actions"> <a href="javascript:;" class="post-like action action-like" data-pid="7078"><i class="fa fa-thumbs-o-up"></i>贊(<span>0</span>)</a> </div> <div class="action-share"></div> <div class="article-tags">標籤:<a href="http://www.ipshop.xyz/tag/ios" rel="tag">iOS</a><a href="http://www.ipshop.xyz/tag/linux" rel="tag">Linux</a><a href="http://www.ipshop.xyz/tag/sql" rel="tag">SQL</a><a href="http://www.ipshop.xyz/tag/%e5%ae%89%e5%85%a8" rel="tag">安全</a></div> <nav class="article-nav"> <span class="article-nav-prev">上一篇<br><a href="http://www.ipshop.xyz/7077.html" rel="prev">機器人學影響 CIO 角色的 3 種方式 | Linux 中國</a></span> <span class="article-nav-next">下一篇<br><a href="http://www.ipshop.xyz/7079.html" rel="next">【每日安全資訊】後門 Docker 映象被下載了超過 500 萬次</a></span> </nav> <div class="relates"><div class="title"><h3>相關推薦</h3></div><ul><li><a href="http://www.ipshop.xyz/18292.html">分庫分表實戰:可能是使用者表最佳分庫分表方案</a></li><li><a href="http://www.ipshop.xyz/18291.html">4 張 GIF 圖幫助你理解二叉搜尋樹</a></li><li><a href="http://www.ipshop.xyz/17827.html">分散式鏈路追蹤 SkyWalking 原始碼分析 —— Agent 收集 Trace 資料</a></li><li><a href="http://www.ipshop.xyz/17784.html">一份來自英偉達的越南小姐姐整理的機器學習入門清單,照這樣學就對了</a></li><li><a href="http://www.ipshop.xyz/17854.html">HBase 資料遷移方案介紹</a></li><li><a href="http://www.ipshop.xyz/17853.html">C# 管道式程式設計</a></li><li><a href="http://www.ipshop.xyz/17787.html">不會SQL註入,連漫畫都看不懂了</a></li><li><a href="http://www.ipshop.xyz/17782.html">向Excel說再見,神級編輯器統一表格與Python</a></li></ul></div> </div> </div> <div class="sidebar"> <div class="widget widget_ui_asb"><div class="item"><script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <!-- ad3 --> <ins class="adsbygoogle" style="display:block" data-ad-client="ca-pub-3715363832600463" data-ad-slot="8216000168" data-ad-format="auto" data-full-width-responsive="true"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script></div></div><div class="widget widget_ui_tags"><h3>熱門標籤</h3><div class="items"><a href="http://www.ipshop.xyz/tag/ios">iOS (11238)</a><a href="http://www.ipshop.xyz/tag/%e5%be%ae%e8%bb%9f">微軟 (4955)</a><a href="http://www.ipshop.xyz/tag/linux">Linux (4274)</a><a href="http://www.ipshop.xyz/tag/%e5%ae%89%e5%85%a8">安全 (4180)</a><a href="http://www.ipshop.xyz/tag/python">Python (4161)</a><a href="http://www.ipshop.xyz/tag/%e6%80%a7%e8%83%bd">效能 (3165)</a><a href="http://www.ipshop.xyz/tag/%e9%81%8b%e7%b6%ad">運維 (2774)</a><a href="http://www.ipshop.xyz/tag/%e5%84%aa%e5%8c%96">最佳化 (2419)</a><a href="http://www.ipshop.xyz/tag/net">.NET (2262)</a><a href="http://www.ipshop.xyz/tag/google">Google (2136)</a><a href="http://www.ipshop.xyz/tag/%e6%a9%9f%e5%99%a8%e5%ad%b8%e7%bf%92">機器學習 (1795)</a><a href="http://www.ipshop.xyz/tag/%e4%bd%b5%e7%99%bc">併發 (1613)</a><a href="http://www.ipshop.xyz/tag/%e5%88%86%e4%bd%88%e5%bc%8f">分散式 (1559)</a><a href="http://www.ipshop.xyz/tag/%e9%9b%86%e7%be%a4">叢集 (1240)</a><a href="http://www.ipshop.xyz/tag/sql">SQL (1174)</a><a href="http://www.ipshop.xyz/tag/mysql">Mysql (1060)</a><a href="http://www.ipshop.xyz/tag/%e5%8d%80%e5%a1%8a%e9%8f%88">區塊鏈 (1017)</a><a href="http://www.ipshop.xyz/tag/docker">Docker (977)</a><a href="http://www.ipshop.xyz/tag/%e5%be%ae%e6%9c%8d%e5%8b%99">微服務 (922)</a><a href="http://www.ipshop.xyz/tag/%e9%9d%a2%e8%a9%a6">面試 (919)</a><a href="http://www.ipshop.xyz/tag/apache">Apache (743)</a><a href="http://www.ipshop.xyz/tag/nlp">NLP (725)</a><a href="http://www.ipshop.xyz/tag/redis">Redis (719)</a><a href="http://www.ipshop.xyz/tag/android">Android (668)</a><a href="http://www.ipshop.xyz/tag/git">Git (640)</a><a href="http://www.ipshop.xyz/tag/%e6%9e%b6%e6%a7%8b%e5%b8%ab">架構師 (632)</a><a href="http://www.ipshop.xyz/tag/nginx">Nginx (630)</a><a href="http://www.ipshop.xyz/tag/facebook">Facebook (599)</a><a href="http://www.ipshop.xyz/tag/jvm">JVM (595)</a><a href="http://www.ipshop.xyz/tag/%e7%88%ac%e8%9f%b2">爬蟲 (476)</a></div></div><div class="widget widget_ui_posts"><h3>熱門文章</h3><ul class="nopic"><li><a href="http://www.ipshop.xyz/15779.html"><span class="text">用 docker-compose 啟動 WebApi 和 SQL Server</span><span class="muted">2019-06-26</span></a></li> <li><a href="http://www.ipshop.xyz/9049.html"><span class="text">電線電纜的平方數及平方數和電流的換算公式</span><span class="muted">2018-04-02</span></a></li> <li><a href="http://www.ipshop.xyz/1250.html"><span class="text">實體 :手把手教你用PyTorch快速準確地建立神經網路(附4個學習用例)</span><span class="muted">2019-02-02</span></a></li> <li><a href="http://www.ipshop.xyz/12632.html"><span class="text">小樣本學習(Few-shot Learning)綜述</span><span class="muted">2019-04-01</span></a></li> <li><a href="http://www.ipshop.xyz/1208.html"><span class="text">面試官讓用5種python方法實現字串反轉?對不起我有16種……</span><span class="muted">2019-01-13</span></a></li> <li><a href="http://www.ipshop.xyz/4542.html"><span class="text">黎曼猜想仍舊,素數依然孤獨</span><span class="muted">2018-09-26</span></a></li> </ul></div></div></section> <div class="branding branding-black"> <div class="container"> <h2>分享創造快樂</h2> </div> </div> <footer class="footer"> <div class="container"> <p>© 2024 <a href="http://www.ipshop.xyz">知識星球</a>   <a href="http://www.ipshop.xyz/sitemap.xml">網站地圖</a> </p> <!-- Global site tag (gtag.js) - Google Analytics --> <script async src="https://www.googletagmanager.com/gtag/js?id=UA-133465382-1"></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-133465382-1'); </script> </div> </footer> <script> window.jsui={ www: 'http://www.ipshop.xyz', uri: 'http://www.ipshop.xyz/wp-content/themes/dux', ver: '5.0', roll: [], ajaxpager: '0', url_rp: '', qq_id: '', qq_tip: '' }; </script> <script type='text/javascript' src='http://www.ipshop.xyz/wp-content/themes/dux/js/libs/bootstrap.min.js?ver=5.0'></script> <script type='text/javascript' src='http://www.ipshop.xyz/wp-content/themes/dux/js/loader.js?ver=5.0'></script> <script type='text/javascript' src='http://www.ipshop.xyz/wp-includes/js/wp-embed.min.js?ver=4.9.25'></script> </body> </html>