这一章实现的是会话管理功能。采用的是cookie+session的方式实现登录功能。
引用了第三方库:github.com/gorilla/sessions
实现了login登录校验以及生成session信息后,我有点茫然:go如何定义一个中间件简单校验是否已登录?
我现在能想到的方案:写个校验是否登录的公共方法,检验成功则返回用户信息,失败则提示用户登录。
然后每个接口都调用一下这个校验方法。
目录架构
user_login.go代码:
package user
import (
"fmt"
"net/http"
"github.com/gorilla/sessions"
sql_pk "database/sql"
storage "etcd_web/storage"
common "etcd_web/common"
conf "etcd_web/config"
)
const COOKIENAME string = "user-cookie"
var (
// key must be 16, 24 or 32 bytes long (AES-128, AES-192 or AES-256)
key = []byte("jay-secret-key")
store = sessions.NewCookieStore(key)
)
//用户登录
func Login(w http.ResponseWriter, r *http.Request) {
user_name := r.FormValue("user_name")
password := r.FormValue("password")
if user_name == "" || password == "" {
common.ReturnError(w, conf.FAIL_CODE, "用户名和密码不能为空")
return
}
//查看用户和密码是否正确
mysqlConnect, err := storage.NewMySqlInit()
sql := "select id,user_name from etcd_admin where user_name = ? and password = ?"
row,err := mysqlConnect.QueryRow(sql,user_name,password)
var UserInfo struct {
User_id int `json:"user_id"`
User_name string `json:"user_name"`
}
err = row.Scan(&UserInfo.User_id,&UserInfo.User_name)
fmt.Println(err)
if err != nil {
if err == sql_pk.ErrNoRows {
common.ReturnError(w, conf.FAIL_CODE, "用户名或密码不正确")
return
} else {
common.ReturnError(w, conf.FAIL_CODE, err.Error())
return
}
}
// fmt.Println(UserInfo)
session, _ := store.Get(r, COOKIENAME)
// Set user as authenticated
session.Values["authenticated"] = true
session.Values["user_id"] = UserInfo.User_id
session.Values["user_name"] = UserInfo.User_name
session.Save(r, w)
common.ReturnSuccess(w, conf.SUCCESS_CODE, "登录成功", UserInfo)
}
//退出登录
func Logout(w http.ResponseWriter, r *http.Request) {
session, _ := store.Get(r, COOKIENAME)
// Revoke users authentication
session.Values["authenticated"] = false
session.Save(r, w)
common.ReturnSuccess(w, conf.SUCCESS_CODE, "退出成功", nil)
}
//测试是否有登录
func TestLogin(w http.ResponseWriter, r *http.Request) {
session, _ := store.Get(r, COOKIENAME)
// Check if user is authenticated
if auth, ok := session.Values["authenticated"].(bool); !ok || !auth {
http.Error(w, "你未登录", http.StatusForbidden)
return
}
user_id := session.Values["user_id"]
user_name := session.Values["user_name"]
fmt.Fprintln(w,user_id)
fmt.Fprintln(w,user_name)
// Print secret message
fmt.Fprintln(w, "你已经登录成功了!")
}
checkLogin.go代码:
package common
import (
"net/http"
"errors"
"github.com/gorilla/sessions"
)
const COOKIENAME string = "kpl-cookie"
var (
// key must be 16, 24 or 32 bytes long (AES-128, AES-192 or AES-256)
key = []byte("kpl-secret-key")
store = sessions.NewCookieStore(key)
)
type UserInfo struct{
user_id interface{} `json:"user_id"`
user_name interface{} `json:"user_name"`
}
//检查用户是否登录,并返回用户信息
func CheckLogin(w http.ResponseWriter, r *http.Request) (*UserInfo,error){
session, _ := store.Get(r, COOKIENAME)
// Check if user is authenticated
if auth, ok := session.Values["authenticated"].(bool); !ok || !auth {
return nil,errors.New("用户还未登录!")
}
var user_info *UserInfo
user_info = new(UserInfo)
user_info.user_id = session.Values["user_id"]
user_info.user_name = session.Values["user_name"]
return user_info,nil
}
接口中校验是否登录:
//删除管理员
func DelAdmin(w http.ResponseWriter, r *http.Request) {
//检查是否已经登录
userInfo,err := common.CheckLogin(w,r)
fmt.Println(userInfo)
if err != nil {
common.ReturnError(w, http.StatusForbidden, "用户未登录")
return
}
var sql string
//获取参数
id := r.FormValue("id")
//参数判断
if id == "" {
common.ReturnError(w, conf.FAIL_CODE, "用户id不能为空")
return
}
//获取数据库连接
mysqlConnect, err := mysql.NewMySqlInit()
if err != nil {
common.ReturnError(w, conf.FAIL_CODE, fmt.Sprintf("连接出错了:%v", err))
return
}
sql = "delete from etcd_admin where id=?"
_, err = mysqlConnect.Exec(sql, id)
if err != nil {
common.ReturnError(w, conf.FAIL_CODE, fmt.Sprintf("删除出错了:%v", err))
return
}
common.ReturnSuccess(w, conf.SUCCESS_CODE, "删除成功", nil)
}
main.go代码:
package main
import (
"net/http"
//内部包
// mysql "etcd_web/storage"
user "etcd_web/user"
etcd "etcd_web/etcd"
)
func main() {
// 当访问 http://127.0.0.1:9527/hello 时,进入这个方法
http.HandleFunc("/hello", HelloHandler)
//设置管理员(方法提取到etcd_web/user目录下的文件)
http.HandleFunc("/addAdmin", user.AddAdmin)
http.HandleFunc("/updateAdmin", user.UpdateAdmin)
http.HandleFunc("/delAdmin", user.DelAdmin)
http.HandleFunc("/getAdminList", user.GetAdminList)
//操作etcd
http.HandleFunc("/getEtcdData", etcd.GetEtcdData)
http.HandleFunc("/getEtcdDataWithPrefix", etcd.GetEtcdDataWithPrefix)
http.HandleFunc("/setEtcdData", etcd.SetEtcdData)
http.HandleFunc("/delEtcdData", etcd.DelEtcdData)
//用户登录
http.HandleFunc("/login",user.Login)
http.HandleFunc("/logout",user.Logout)
http.HandleFunc("/testLogin",user.TestLogin)
// 启动一个Web服务,并监听9527端口
http.ListenAndServe(":9527",nil)
}
//测试方法
func HelloHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello World
"))
}