Go 用戶認證

2022-05-13 16:54 更新

在開發(fā)Web應(yīng)用過程中,用戶認證是開發(fā)者經(jīng)常遇到的問題,用戶登錄、注冊、登出等操作,而一般認證也分為三個方面的認證

  • HTTP Basic和 HTTP Digest認證
  • 第三方集成認證:QQ、微博、豆瓣、OPENID、google、github、facebook和twitter等
  • 自定義的用戶登錄、注冊、登出,一般都是基于session、cookie認證

beego目前沒有針對這三種方式進行任何形式的集成,但是可以充分的利用第三方開源庫來實現(xiàn)上面的三種方式的用戶認證,不過后續(xù)beego會對前面兩種認證逐步集成。

HTTP Basic和 HTTP Digest認證

這兩個認證是一些應(yīng)用采用的比較簡單的認證,目前已經(jīng)有開源的第三方庫支持這兩個認證:

github.com/abbot/go-http-auth 

下面代碼演示了如何把這個庫引入beego中從而實現(xiàn)認證:

package controllers

import (
    "github.com/abbot/go-http-auth"
    "github.com/astaxie/beego"
)

func Secret(user, realm string) string {
    if user == "john" {
        // password is "hello"
        return "$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1"
    }
    return ""
}

type MainController struct {
    beego.Controller
}

func (this *MainController) Prepare() {
    a := auth.NewBasicAuthenticator("example.com", Secret)
    if username := a.CheckAuth(this.Ctx.Request); username == "" {
        a.RequireAuth(this.Ctx.ResponseWriter, this.Ctx.Request)
    }
}

func (this *MainController) Get() {
    this.Data["Username"] = "astaxie"
    this.Data["Email"] = "astaxie@gmail.com"
    this.TplNames = "index.tpl"
}

上面代碼利用了beego的prepare函數(shù),在執(zhí)行正常邏輯之前調(diào)用了認證函數(shù),這樣就非常簡單的實現(xiàn)了http auth,digest的認證也是同樣的原理。

oauth和oauth2的認證

oauth和oauth2是目前比較流行的兩種認證方式,還好第三方有一個庫實現(xiàn)了這個認證,但是是國外實現(xiàn)的,并沒有QQ、微博之類的國內(nèi)應(yīng)用認證集成:

github.com/bradrydzewski/go.auth

下面代碼演示了如何把該庫引入beego中從而實現(xiàn)oauth的認證,這里以github為例演示:

  1. 添加兩條路由

    beego.RegisterController("/auth/login", &controllers.GithubController{})
    beego.RegisterController("/mainpage", &controllers.PageController{})
  2. 然后我們處理GithubController登陸的頁面:

    package controllers
    
    import (
        "github.com/astaxie/beego"
        "github.com/bradrydzewski/go.auth"
    )
    
    const (
        githubClientKey = "a0864ea791ce7e7bd0df"
        githubSecretKey = "a0ec09a647a688a64a28f6190b5a0d2705df56ca"
    )
    
    type GithubController struct {
        beego.Controller
    }
    
    func (this *GithubController) Get() {
        // set the auth parameters
        auth.Config.CookieSecret = []byte("7H9xiimk2QdTdYI7rDddfJeV")
        auth.Config.LoginSuccessRedirect = "/mainpage"
        auth.Config.CookieSecure = false
    
        githubHandler := auth.Github(githubClientKey, githubSecretKey)
    
        githubHandler.ServeHTTP(this.Ctx.ResponseWriter, this.Ctx.Request)
    }
  3. 處理登陸成功之后的頁面

    package controllers
    
    import (
        "github.com/astaxie/beego"
        "github.com/bradrydzewski/go.auth"
        "net/http"
        "net/url"
    )
    
    type PageController struct {
        beego.Controller
    }
    
    func (this *PageController) Get() {
        // set the auth parameters
        auth.Config.CookieSecret = []byte("7H9xiimk2QdTdYI7rDddfJeV")
        auth.Config.LoginSuccessRedirect = "/mainpage"
        auth.Config.CookieSecure = false
    
        user, err := auth.GetUserCookie(this.Ctx.Request)
    
        //if no active user session then authorize user
        if err != nil || user.Id() == "" {
            http.Redirect(this.Ctx.ResponseWriter, this.Ctx.Request, auth.Config.LoginRedirect, http.StatusSeeOther)
            return
        }
    
        //else, add the user to the URL and continue
        this.Ctx.Request.URL.User = url.User(user.Id())
        this.Data["pic"] = user.Picture()
        this.Data["id"] = user.Id()
        this.Data["name"] = user.Name()
        this.TplNames = "home.tpl"
    }

整個的流程如下,首先打開瀏覽器輸入地址:

  1. 整個的流程如下,首先打開瀏覽器輸入地址:

用戶認證 - 圖1

圖14.4 顯示帶有登錄按鈕的首頁

然后點擊鏈接出現(xiàn)如下界面:

用戶認證 - 圖2

圖14.5 點擊登錄按鈕后顯示github的授權(quán)頁

然后點擊Authorize app就出現(xiàn)如下界面:

用戶認證 - 圖3

圖14.6 授權(quán)登錄之后顯示的獲取到的github信息頁

自定義認證

自定義的認證一般都是和session結(jié)合驗證的,如下代碼來源于一個基于beego的開源博客:

//登陸處理
func (this *LoginController) Post() {
	this.TplNames = "login.tpl"
	this.Ctx.Request.ParseForm()
	username := this.Ctx.Request.Form.Get("username")
	password := this.Ctx.Request.Form.Get("password")
	md5Password := md5.New()
	io.WriteString(md5Password, password)
	buffer := bytes.NewBuffer(nil)
	fmt.Fprintf(buffer, "%x", md5Password.Sum(nil))
	newPass := buffer.String()

	now := time.Now().Format("2006-01-02 15:04:05")

	userInfo := models.GetUserInfo(username)
	if userInfo.Password == newPass {
		var users models.User
		users.Last_logintime = now
		models.UpdateUserInfo(users)

		//登錄成功設(shè)置session
		sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
		sess.Set("uid", userInfo.Id)
		sess.Set("uname", userInfo.Username)

		this.Ctx.Redirect(302, "/")
	}	
}

//注冊處理
func (this *RegController) Post() {
	this.TplNames = "reg.tpl"
	this.Ctx.Request.ParseForm()
	username := this.Ctx.Request.Form.Get("username")
	password := this.Ctx.Request.Form.Get("password")
	usererr := checkUsername(username)
	fmt.Println(usererr)
	if usererr == false {
		this.Data["UsernameErr"] = "Username error, Please to again"
		return
	}

	passerr := checkPassword(password)
	if passerr == false {
		this.Data["PasswordErr"] = "Password error, Please to again"
		return
	}

	md5Password := md5.New()
	io.WriteString(md5Password, password)
	buffer := bytes.NewBuffer(nil)
	fmt.Fprintf(buffer, "%x", md5Password.Sum(nil))
	newPass := buffer.String()

	now := time.Now().Format("2006-01-02 15:04:05")

	userInfo := models.GetUserInfo(username)

	if userInfo.Username == "" {
		var users models.User
		users.Username = username
		users.Password = newPass
		users.Created = now
		users.Last_logintime = now
		models.AddUser(users)

		//登錄成功設(shè)置session
		sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
		sess.Set("uid", userInfo.Id)
		sess.Set("uname", userInfo.Username)
		this.Ctx.Redirect(302, "/")
	} else {
		this.Data["UsernameErr"] = "User already exists"
	}

}

func checkPassword(password string) (b bool) {
	if ok, _ := regexp.MatchString("^[a-zA-Z0-9]{4,16}$", password); !ok {
		return false
	}
	return true
}

func checkUsername(username string) (b bool) {
	if ok, _ := regexp.MatchString("^[a-zA-Z0-9]{4,16}$", username); !ok {
		return false
	}
	return true
}

有了用戶登陸和注冊之后,其他模塊的地方可以增加如下這樣的用戶是否登陸的判斷:

func (this *AddBlogController) Prepare() {
	sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
	sess_uid := sess.Get("userid")
	sess_username := sess.Get("username")
	if sess_uid == nil {
		this.Ctx.Redirect(302, "/admin/login")
		return
	}
	this.Data["Username"] = sess_username
}
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號