在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ GO/ 14.4 用戶認(rèn)證
7 文本處理
3 Web基礎(chǔ)
14 擴(kuò)展Web框架
10.4 小結(jié)
2.2 Go基礎(chǔ)
2.8 總結(jié)
6.1 session和cookie
5.5 使用beedb庫(kù)進(jìn)行ORM開發(fā)
8.3 REST
13.6 小結(jié)
5.4 使用PostgreSQL數(shù)據(jù)庫(kù)
14.6 pprof支持
14.1 靜態(tài)文件支持
11.2 使用GDB調(diào)試
7.7 小結(jié)
1 GO環(huán)境配置
14.5 多語(yǔ)言支持
7.1 XML處理
1.5 總結(jié)
13 如何設(shè)計(jì)一個(gè)Web框架
14.3 表單及驗(yàn)證支持
12 部署與維護(hù)
10 國(guó)際化和本地化
1.1 Go 安裝
6.2 Go如何使用session
5.6 NOSQL數(shù)據(jù)庫(kù)操作
6.5 小結(jié)
9.4 避免SQL注入
12.1 應(yīng)用日志
4.2 驗(yàn)證表單的輸入
10.1 設(shè)置默認(rèn)地區(qū)
1.3 Go 命令
9.6 加密和解密數(shù)據(jù)
4.1 處理表單的輸入
4.4 防止多次遞交表單
11.3 Go怎么寫測(cè)試用例
8 Web服務(wù)
12.3 應(yīng)用部署
5.7 小結(jié)
12.5 小結(jié)
11 錯(cuò)誤處理,調(diào)試和測(cè)試
9.2 確保輸入過(guò)濾
14.2 Session支持
6.4 預(yù)防session劫持
12.4 備份和恢復(fù)
8.1 Socket編程
13.1 項(xiàng)目規(guī)劃
13.4 日志和配置設(shè)計(jì)
7.6 字符串處理
13.2 自定義路由器設(shè)計(jì)
6.3 session存儲(chǔ)
3.4 Go的http包詳解
8.2 WebSocket
10.3 國(guó)際化站點(diǎn)
7.5 文件操作
7.4 模板處理
9.1 預(yù)防CSRF攻擊
13.3 controller設(shè)計(jì)
2.6 interface
14.4 用戶認(rèn)證
2.3 流程和函數(shù)
附錄A 參考資料
11.1 錯(cuò)誤處理
9.5 存儲(chǔ)密碼
9.3 避免XSS攻擊
12.2 網(wǎng)站錯(cuò)誤處理
6 session和數(shù)據(jù)存儲(chǔ)
2.4 struct類型
3.3 Go如何使得Web工作
2.5 面向?qū)ο?/span>
3.1 Web工作方式
1.2 GOPATH與工作空間
2.1 你好,Go
9.7 小結(jié)
13.5 實(shí)現(xiàn)博客的增刪改
7.2 JSON處理
10.2 本地化資源
7.3 正則處理
2 Go語(yǔ)言基礎(chǔ)
5.1 database/sql接口
4.5 處理文件上傳
8.5 小結(jié)
4.3 預(yù)防跨站腳本
5.3 使用SQLite數(shù)據(jù)庫(kù)
14.7 小結(jié)
3.2 Go搭建一個(gè)Web服務(wù)器
2.7 并發(fā)
5 訪問(wèn)數(shù)據(jù)庫(kù)
4 表單
3.5 小結(jié)
1.4 Go開發(fā)工具
11.4 小結(jié)
9 安全與加密
5.2 使用MySQL數(shù)據(jù)庫(kù)
4.6 小結(jié)
8.4 RPC

14.4 用戶認(rèn)證

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

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

beego目前沒(méi)有針對(duì)這三種方式進(jìn)行任何形式的集成,但是可以充分的利用第三方開源庫(kù)來(lái)實(shí)現(xiàn)上面的三種方式的用戶認(rèn)證,不過(guò)后續(xù)beego會(huì)對(duì)前面兩種認(rèn)證逐步集成。

HTTP Basic和 HTTP Digest認(rèn)證

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

github.com/abbot/go-http-auth 

下面代碼演示了如何把這個(gè)庫(kù)引入beego中從而實(shí)現(xiàn)認(rè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)用了認(rèn)證函數(shù),這樣就非常簡(jiǎn)單的實(shí)現(xiàn)了http auth,digest的認(rèn)證也是同樣的原理。

oauth和oauth2的認(rèn)證

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

github.com/bradrydzewski/go.auth

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

  1. 添加兩條路由

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

      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. 處理登陸成功之后的頁(yè)面

      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"
      }

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

http://wiki.jikexueyuan.com/project/go-web-programming/images/14.4.github.png" alt="" />

圖14.4 顯示帶有登錄按鈕的首頁(yè)

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

http://wiki.jikexueyuan.com/project/go-web-programming/images/14.4.github2.png" alt="" />

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

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

http://wiki.jikexueyuan.com/project/go-web-programming/images/14.4.github3.png" alt="" />

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

自定義認(rèn)證

自定義的認(rèn)證一般都是和session結(jié)合驗(yàn)證的,如下代碼來(lái)源于一個(gè)基于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, "/")
    }   
}

//注冊(cè)處理
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
}

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

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
}