程序目錄結構

簡單實現,用戶登錄后返回一個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#類的說明那種)
