当前位置: 首页 > 科技观察

无密码认证:服务器登录更安全

时间:2023-03-22 14:50:22 科技观察

无密码认证让您无需输入密码,只需输入邮箱即可登录系统。这是一种比传统电子邮件/密码验证更安全的登录方法。下面我将向您展示如何在Go中实现一个HTTPAPI来提供此服务。流程用户输入他的电子邮件地址。服务器创建一个与用户关联的临时一次性代码(如临时密码),然后向用户的邮箱发送一个“魔术链接”。用户点击魔法链接。服务器提取魔术链接中的代码,获取关联的用户,并使用新的JWT重定向到客户端。客户端使用JWT对每个新请求的用户进行身份验证。先决条件数据库:我们为此服务使用名为CockroachDB的SQL数据库。它非常像postgres,但是是用Go编写的。SMTP服务器:我们将使用第三方邮件服务器来发送电子邮件。开发时我们使用mailtrap。Mailtrap将所有电子邮件发送到其收件箱,因此您在测试时无需创建多个虚假电子邮件帐户。从Go主页安装它,然后使用goversion(1.10.1atm)命令检查它是否有效。从CockroachDB主页下载它,展开它并将它添加到您的PATH变量中。使用蟑螂版本(2.0atm)命令检查它是否有效。DatabaseSchema现在,我们在这个项目的GOPATH目录下创建一个目录,然后使用cockroachstart启动一个新的CockroachDB节点:cockroachstart--insecure--host127.0.0.1它会输出一些东西,找到SQL地址行,它会显示类似postgresql://root@127.0.0.1:26257?sslmode=disable的内容。稍后我们将使用它来连接数据库。创建具有以下内容的schema.sql文件。如果存在passwordless_demoCASCADE,则删除数据库;如果不存在,则创建数据库passwordless_demo;设置数据库=passwordless_demo;如果不存在,则创建表(idUUIDPRIMARYKEYDEFAULTgen_random_uuid(),user_idUUIDNOTNULLREFERENCES用户ONDELETECASCADE,created_atTIMESTAMPTZNOTNULLDEFAULTnow());INSERTINTOusers(email,username)VALUES('john@passwordless.local_do','');该脚本创建一个名为passwordless_demo的数据库,两个名为users和verification_codes的表,并插入一些假用户以供以后测试。每个验证码都与用户关联并保存创建时间,用于检查验证码是否过期。在另一个终端中使用cockroachsql命令运行此脚本:catschema.sql|cockroachsql--insecure环境配置需要配置两个环境变量:SMTP_USERNAME和SMTP_PASSWORD,你可以从你的mailtrap账户中获取。我们将在我们的程序中使用它们。Go依赖我们需要以下Go包:github.com/lib/pq:它是CockroachDB使用的postgres驱动程序github.com/matryer/way:路由器github.com/dgrijalva/jwt-go:JWT实现goget-ugithub.com/lib/pqgoget-ugithub.com/matryer/waygoget-ugithub.com/dgrijalva/jwt-go代码初始化函数创建main.go并开始从init中的环境变量获取一些配置功能。varconfigstruct{portintappURL*url.URLdatabaseURLstringjwtKey[]bytesmtpAddrstringsmtpAuthsmtp.Auth}funcinit(){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{日志.Fatalln("在环境变量上找不到SMTP_USERNAME")}smtpPassword,ok:=os.LookupEnv("SMTP_PASSWORD")if!ok{log.Fatalln("在环境变量中找不到SMTP_PASSWORD")}config.smtpAuth=smtp.PlainAuth("",smtpUsername,smtpPassword,smtpHost)}funcenv(key,fallbackValuestring)string{v,ok:=os.LookupEnv(key)if!ok{returnfallbackValue}returnv}appURL将构建我们的“魔术链接”端口将启动的HTTP服务器。databaseURL是CockroachDB地址,我在之前添加了/passwordless_demo数据库地址表示数据库名称,jwtKey用于签署JWT,smtpAddr是SMTP_HOST+SMTP_PORT的组合,我们将用它来发送邮件,smtpUsername和smtpPassword是两个必需的变量,smtpAuth也用于发送邮件,env函数allows我们获取环境变量,如果它不存在则返回一个回退值。主函数vardb*sql.DBfuncmain(){varerrerrorifdb,err=sql.Open("postgres",config.databaseURL);err!=nil{log.Fatalf("无法打开数据库连接:%v\n",err)}deferdb.Close()iferr=db.Ping();err!=nil{log.Fatalf("无法ping到数据库:%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("在%s启动服务器