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

下面我將為你展示,如何在 Go 中實現(xiàn)一個 HTTP API 去提供這種服務。
流程
- 用戶輸入他的電子郵件地址。
- 服務器創(chuàng)建一個臨時的一次性使用的代碼(就像一個臨時密碼一樣)關聯(lián)到用戶,然后給用戶郵箱中發(fā)送一個“魔法鏈接”。
- 用戶點擊魔法鏈接。
- 服務器提取魔法鏈接中的代碼,獲取關聯(lián)的用戶,并且使用一個新的 JWT 重定向到客戶端。
- 在每次有新請求時,客戶端使用 JWT 去驗證用戶。
必需條件
- 數(shù)據(jù)庫:我們?yōu)檫@個服務使用了一個叫 CockroachDB 的 SQL 數(shù)據(jù)庫。它非常像 postgres,但它是用 Go 寫的。
- SMTP 服務器:我們將使用一個第三方的郵件服務器去發(fā)送郵件。開發(fā)的時我們使用 mailtrap。Mailtrap 發(fā)送所有的郵件到它的收件箱,因此,你在測試時不需要創(chuàng)建多個假郵件帳戶。
從 Go 的主頁 上安裝它,然后使用 go version(1.10.1 atm)命令去檢查它能否正常工作。
從 CockroachDB 的主頁 上下載它,展開它并添加到你的 PATH 變量中。使用 cockroach version(2.0 atm)命令檢查它能否正常工作。
數(shù)據(jù)庫模式
現(xiàn)在,我們在 GOPATH 目錄下為這個項目創(chuàng)建一個目錄,然后使用 cockroach start 啟動一個新的 CockroachDB 節(jié)點:
cockroach start --insecure --host 127.0.0.1
它會輸出一些內(nèi)容,找到 SQL 地址行,它將顯示像 postgresql://root@127.0.0.1:26257?sslmode=disable 這樣的內(nèi)容。稍后我們將使用它去連接到數(shù)據(jù)庫。
使用如下的內(nèi)容去創(chuàng)建一個 schema.sql 文件。
DROP DATABASE IF EXISTS passwordless_demo CASCADE;CREATE DATABASE IF NOT EXISTS passwordless_demo;SET DATABASE = passwordless_demo;CREATE TABLE IF NOT EXISTS users (id UUID PRIMARY KEY DEFAULT gen_random_uuid(),email STRING UNIQUE,username STRING UNIQUE);CREATE TABLE IF NOT EXISTS verification_codes (id UUID PRIMARY KEY DEFAULT gen_random_uuid(),user_id UUID NOT NULL REFERENCES users ON DELETE CASCADE,created_at TIMESTAMPTZ NOT NULL DEFAULT now());INSERT INTO users (email, username) VALUES('john@passwordless.local', 'john_doe');
這個腳本創(chuàng)建了一個名為 passwordless_demo 的數(shù)據(jù)庫、兩個名為 users 和 verification_codes 的表,以及為了稍后測試而插入的一些假用戶。每個驗證代碼都與用戶關聯(lián)并保存創(chuàng)建時間,以用于去檢查驗證代碼是否過期。
在另外的終端中使用 cockroach sql 命令去運行這個腳本:
cat schema.sql | cockroach sql --insecure
環(huán)境配置
需要配置兩個環(huán)境變量:SMTP_USERNAME 和 SMTP_PASSWORD,你可以從你的 mailtrap 帳戶中獲得它們。將在我們的程序中用到它們。
Go 依賴
我們需要下列的 Go 包:
- github.com/lib/pq:它是 CockroachDB 使用的 postgres 驅(qū)動
- github.com/matryer/way: 路由器
- github.com/dgrijalva/jwt-go: JWT 實現(xiàn)
go get -u github.com/lib/pqgo get -u github.com/matryer/waygo get -u github.com/dgrijalva/jwt-go
代碼
初始化函數(shù)
創(chuàng)建 main.go 并且通過 init 函數(shù)里的環(huán)境變量中取得一些配置來啟動。
var config struct {port intappURL *url.URLdatabaseURL stringjwtKey []bytesmtpAddr stringsmtpAuth smtp.Auth}func init() {config.port, _ = strconv.Atoi(env("PORT", "80"))config.appURL, _ = url.Parse(env("APP_URL", "http://localhost:"+strconv.Itoa(config.port)+"/"))config.databaseURL = env("DATABASE_URL", "postgresql://root@127.0.0.1:26257/passwordless_demo?sslmode=disable")config.jwtKey = []byte(env("JWT_KEY", "super-duper-secret-key"))smtpHost := env("SMTP_HOST", "smtp.mailtrap.io")config.smtpAddr = net.JoinHostPort(smtpHost, env("SMTP_PORT", "25"))smtpUsername, ok := os.LookupEnv("SMTP_USERNAME")if !ok {log.Fatalln("could not find SMTP_USERNAME on environment variables")}smtpPassword, ok := os.LookupEnv("SMTP_PASSWORD")if !ok {log.Fatalln("could not find SMTP_PASSWORD on environment variables")}config.smtpAuth = smtp.PlainAuth("", smtpUsername, smtpPassword, smtpHost)}func env(key, fallbackValue string) string {v, ok := os.LookupEnv(key)if !ok {return fallbackValue}return v}
appURL將去構建我們的 “魔法鏈接”。port將要啟動的 HTTP 服務器。databaseURL是 CockroachDB 地址,我添加/passwordless_demo前面的數(shù)據(jù)庫地址去表示數(shù)據(jù)庫名字。jwtKey用于簽名 JWT。smtpAddr是SMTP_HOST+SMTP_PORT的聯(lián)合;我們將使用它去發(fā)送郵件。smtpUsername和smtpPassword是兩個必需的變量。smtpAuth也是用于發(fā)送郵件。
env 函數(shù)允許我們?nèi)カ@得環(huán)境變量,不存在時返回一個回退值。
主函數(shù)
var db *sql.DBfunc main() {var err errorif db, err = sql.Open("postgres", config.databaseURL); err != nil {log.Fatalf("could not open database connection: %v\n", err)}defer db.Close()if err = db.Ping(); err != nil {log.Fatalf("could not ping to database: %v\n", err)}router := way.NewRouter()router.HandleFunc("POST", "/api/users", jsonRequired(createUser))router.HandleFunc("POST", "/api/passwordless/start", jsonRequired(passwordlessStart))router.HandleFunc("GET", "/api/passwordless/verify_redirect", passwordlessVerifyRedirect)router.Handle("GET", "/api/auth_user", authRequired(getAuthUser))addr := fmt.Sprintf(":%d", config.port)log.Printf("starting server at %s
分享文章:無密碼驗證:服務器 登錄更安全
網(wǎng)站路徑:http://www.dlmjj.cn/article/djecoos.html


咨詢
建站咨詢
