在 Web 开发中,用户身份验证是确保应用安全性的重要环节。本文将全面讲解如何在 Golang 中利用 session cookie 实现用户身份验证。通过该教程,您将学会如何创建登录、会话验证和用户登出等功能,使应用更安全且用户体验更友好。
1. 什么是 Session Cookie?
Session cookie 是一种存储在用户浏览器中的小型数据包,用于在用户会话期间维护其状态。当用户登录成功后,服务器会创建一个 session,将其信息保存为 cookie,并在后续请求中使用该 cookie 进行身份验证。
项目概览
本教程将带您创建一个简单的 Golang 应用程序,包含以下两个核心路由:
/signin
路由:接收用户名和密码,验证成功后设置 session cookie。/welcome
路由:显示用户的个性化欢迎消息。
在开发阶段,我们将使用内存来存储会话信息,以便更好地理解原理。实际生产环境中,建议将会话存储在数据库或分布式缓存系统中以提高可靠性。
2. Golang HTTP 服务器配置
首先,我们需要初始化一个 HTTP 服务器,并定义基本路由:
package main
import (
"log"
"net/http"
)
func main() {
http.HandleFunc("/signin", Signin)
http.HandleFunc("/welcome", Welcome)
log.Fatal(http.ListenAndServe(":8080", nil))
}
3. 创建用户会话逻辑
用户登录后,我们将创建一个唯一的会话令牌。为简便起见,我们将使用内存中的 map 来存储用户凭证和会话信息。
var users = map[string]string{
"user1": "password1",
"user2": "password2",
}
var sessions = map[string]session{}
type session struct {
username string
expiry time.Time
}
func (s session) isExpired() bool {
return s.expiry.Before(time.Now())
}
4. 用户登录:设置 Session Cookie
定义 Signin
处理程序,用于接收用户登录请求并在成功后创建一个 session cookie:
type Credentials struct {
Password string `json:"password"`
Username string `json:"username"`
}
func Signin(w http.ResponseWriter, r *http.Request) {
var creds Credentials
err := json.NewDecoder(r.Body).Decode(&creds)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
expectedPassword, ok := users[creds.Username]
if !ok || expectedPassword != creds.Password {
w.WriteHeader(http.StatusUnauthorized)
return
}
sessionToken := uuid.NewString()
expiresAt := time.Now().Add(120 * time.Second)
sessions[sessionToken] = session{
username: creds.Username,
expiry: expiresAt,
}
http.SetCookie(w, &http.Cookie{
Name: "session_token",
Value: sessionToken,
Expires: expiresAt,
})
}
通过上述代码,服务器会生成一个 session_token 并存储在 cookie 中。用户请求时,该 session cookie 将随之发送,便于在后续请求中对其身份进行验证。
5. 验证用户身份
接下来实现 Welcome
处理程序,验证用户的 session_token:
func Welcome(w http.ResponseWriter, r *http.Request) {
c, err := r.Cookie("session_token")
if err != nil {
if err == http.ErrNoCookie {
w.WriteHeader(http.StatusUnauthorized)
return
}
w.WriteHeader(http.StatusBadRequest)
return
}
sessionToken := c.Value
userSession, exists := sessions[sessionToken]
if !exists || userSession.isExpired() {
delete(sessions, sessionToken)
w.WriteHeader(http.StatusUnauthorized)
return
}
w.Write([]byte(fmt.Sprintf("Welcome %s!", userSession.username)))
}
Welcome
处理程序会检查用户的 session 是否有效。如果 session 不存在或已过期,用户将会收到 401 未授权响应。
6. 刷新 Session Token:保持登录状态
为确保用户长时间在线,我们需要刷新其 session token。新增一个 /refresh
路由,用于在会话即将过期时更新 token:
func Refresh(w http.ResponseWriter, r *http.Request) {
c, err := r.Cookie("session_token")
if err != nil {
if err == http.ErrNoCookie {
w.WriteHeader(http.StatusUnauthorized)
return
}
w.WriteHeader(http.StatusBadRequest)
return
}
sessionToken := c.Value
userSession, exists := sessions[sessionToken]
if !exists || userSession.isExpired() {
delete(sessions, sessionToken)
w.WriteHeader(http.StatusUnauthorized)
return
}
newSessionToken := uuid.NewString()
expiresAt := time.Now().Add(120 * time.Second)
sessions[newSessionToken] = session{
username: userSession.username,
expiry: expiresAt,
}
delete(sessions, sessionToken)
http.SetCookie(w, &http.Cookie{
Name: "session_token",
Value: newSessionToken,
Expires: expiresAt,
})
}
7. 用户登出:清除会话
实现 Logout
处理程序,便于用户退出时删除服务器和客户端的会话信息:
func Logout(w http.ResponseWriter, r *http.Request) {
c, err := r.Cookie("session_token")
if err != nil {
if err == http.ErrNoCookie {
w.WriteHeader(http.StatusUnauthorized)
return
}
w.WriteHeader(http.StatusBadRequest)
return
}
sessionToken := c.Value
delete(sessions, sessionToken)
http.SetCookie(w, &http.Cookie{
Name: "session_token",
Value: "",
Expires: time.Now(),
})
}
8. 启动与测试应用程序
通过命令行构建并运行该应用程序,使用支持 cookie 的 HTTP 客户端(如 Postman 或浏览器)测试以下功能:
- 登录:
POST http://localhost:8080/signin
- 获取欢迎消息:
GET http://localhost:8080/welcome
- 刷新会话:
POST http://localhost:8080/refresh
- 登出:
GET http://localhost:8080/logout
总结
本教程演示了如何在 Golang 应用中使用 session cookie 实现用户身份验证。随着应用的发展,可进一步增强数据存储的安全性和一致性,以确保用户数据的安全和隐私。
相关阅读推荐:使用 Golang 构建基于 JWT 的身份验证系统