golang簡單實現jwt驗證(beego、xorm、jwt)
阿新 • • 發佈:2019-01-12
程式目錄結構
簡單實現,使用者登入後返回一個jwt的token,下次請求帶上token請求使用者資訊介面並返回資訊。
app.conf檔案內容(可以用個beego直接讀取裡面的內容)寫的是一個jwt的secretkey
jwtkey="12345678"
config.json裡面儲存的是連線資料庫的使用者名稱和密碼(這裡只是學習如何讀取json的配置檔案,可以整合到beego的app.conf檔案裡)
{ "sqltype":"mssql" ,"connstring":"server=.;port=1433;user id=sa;password=123;database=table1" }
MSSqlHelper.go實現連線mssqlserver的資料庫
package mssqlhelper import ( "fmt" "github.com/akkuman/parseConfig" _ "github.com/denisenkom/go-mssqldb" "github.com/go-xorm/core" "github.com/go-xorm/xorm" ) // 建立 XORM 客戶端 func CreateClient() *xorm.Engine { var config = parseConfig.New("config.json") sqltype := config.Get("sqltype") fmt.Println(sqltype) connstring := config.Get("connstring") fmt.Println(connstring) engine, err := xorm.NewEngine(sqltype.(string), connstring.(string)) if err != nil { println("open error:", &err) } engine.SetMapper(core.SameMapper{}) //表示Struct的類的名稱和資料庫中相同 engine.ShowSQL(true) //顯示SQL語句 engine.Logger().SetLevel(core.LOG_DEBUG) //列印SQL語句 return engine }
AuthorizeController.go實現使用者登入、獲取使用者資訊介面
package controller import ( "GoApi/DAL" "GoApi/Model" "encoding/json" "fmt" "net/http" "strconv" "strings" "time" "github.com/astaxie/beego/context" "github.com/astaxie/beego" jwt "github.com/dgrijalva/jwt-go" "github.com/go-xorm/xorm" ) var engine *xorm.Engine type AuthorizeController struct { beego.Controller } var filterUser = func(ctx *context.Context) { token := ctx.Input.Header("Authorization") b, _ := CheckToken(token) //驗證Token是否合法 if !b { http.Error(ctx.ResponseWriter, "Token verification not pass", http.StatusBadRequest) return } fmt.Println("Request token:", token) } func init() { engine = mssqlhelper.CreateClient() //訪問介面前驗證token beego.InsertFilter("/Authorize/Userinfo", beego.BeforeRouter, filterUser) } type Token struct { Token string `json:"token"` } func fatal(err error) { if err != nil { beego.Error(err) } } //登入 func (this *AuthorizeController) Login() { var user Model.LoginModel // url?username=111&password=222 這種形式 user.UserName = this.GetString("username") user.PassWord = this.GetString("password") //err := this.ParseForm(&user) //接收application/x-www-form-urlencoded形式POST傳遞資料,如Username=111&Password=2222 // err := json.NewDecoder(this.Ctx.Request.Body).Decode(&user) //接收json形式Post的資料 loginuser := &Model.Usertable{Userloginname: user.UserName} has, err := engine.Get(loginuser) if err != nil { fatal(err) } if !has { fatal(err) http.Error(this.Ctx.ResponseWriter, "User Not Exist", http.StatusBadRequest) return } if user.PassWord != loginuser.Userloginpwd { this.Ctx.Output.Header("SetStatus", strconv.Itoa(http.StatusBadRequest)) http.Error(this.Ctx.ResponseWriter, "Password Wrong", http.StatusBadRequest) return } claims := make(jwt.MapClaims) claims["exp"] = time.Now().Add(time.Hour * time.Duration(1)).Unix() claims["iat"] = time.Now().Unix() claims["nameid"] = loginuser.Userloginname claims["User"] = "true" token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) tokenString, err := token.SignedString([]byte(beego.AppConfig.String("jwtkey"))) if err != nil { this.Ctx.Output.Header("SetStatus", strconv.Itoa(http.StatusInternalServerError)) fatal(err) http.Error(this.Ctx.ResponseWriter, "Server is Wrong", http.StatusInternalServerError) return } fmt.Println("Token:", tokenString) this.Ctx.WriteString(fmt.Sprintf("{\"Token\":\"%s\"}", tokenString)) } func (this *AuthorizeController) Userinfo() { token := this.Ctx.Input.Header("Authorization") b, t := CheckToken(token) if !b { this.Ctx.WriteString(fmt.Sprintf("Error:%s", token)) return } loginuser := &Model.Usertable{Userloginname: claims["nameid"].(string)} has, err := engine.Get(loginuser) if err != nil { fatal(err) } if !has { fatal(err) http.Error(this.Ctx.ResponseWriter, "User Not Exist", http.StatusBadRequest) return } data, err := json.Marshal(loginuser) if err != nil { fmt.Println(err) } this.Ctx.WriteString(fmt.Sprintf("{\"Token\":\"%s\",\"User\":%s}", token, string(data))) } // 校驗token是否有效 func CheckToken(token string) (b bool, t *jwt.Token) { kv := strings.Split(token, " ") if len(kv) != 2 || kv[0] != "Bearer" { beego.Error("AuthString invalid:", token) return false, nil } t, err := jwt.Parse(kv[1], func(*jwt.Token) (interface{}, error) { return []byte(beego.AppConfig.String("jwtkey")), nil }) fmt.Println(t) if err != nil { fmt.Println("轉換為jwt claims失敗.", err) return false, nil } return true, t }
LoginModel.go 提交登入使用者名稱和密碼的結構
package Model type LoginModel struct { UserName string `xorm:"VARCHAR(50)"` PassWord string `xorm:"VARCHAR(50)"` }
UserTable.go 使用者資訊實體結構
package Model type Usertable struct { Userid int `xorm:"not null pk INT(4)"` Userloginname string `xorm:"VARCHAR(50)"` Userloginpwd string `xorm:"VARCHAR(50)"` Username string `xorm:"NVARCHAR(200)"` Usermobile string `xorm:"VARCHAR(11)"` Userislock int `xorm:"BIT(1)"` }
main.go中通過beego啟動http的web服務
package main import ( "GoApi/controller" "github.com/astaxie/beego" ) func main() { beego.AutoRouter(&controller.AuthorizeController{}) beego.Run() }
下一步
1、學習如何在攔截器裡攔截驗證後把某個結果值傳遞給要訪問的介面(目前是在接口裡重新解析一遍jwt的token)
2、beego如何實現只允許post訪問某個controller的介面(AutoRouter模式下
)
3、Struct如何實現中文的說明(就是滑鼠放上去會顯示中文描述,類似C#類的說明那種)