Merging other languages
This commit is contained in:
523
en/14.4.md
523
en/14.4.md
@@ -1,259 +1,264 @@
|
||||
# 14.4 用户认证
|
||||
在开发Web应用过程中,用户认证是开发者经常遇到的问题,用户登录、注册、登出等操作,而一般认证也分为三个方面的认证
|
||||
|
||||
- HTTP Basic和 HTTP Digest认证
|
||||
- 第三方集成认证:QQ、微博、豆瓣、OPENID、google、github、facebook和twitter等
|
||||
- 自定义的用户登录、注册、登出,一般都是基于session、cookie认证
|
||||
|
||||
beego目前没有针对这三种方式进行任何形式的集成,但是可以充分的利用第三方开源库来实现上面的三种方式的用户认证,不过后续beego会对前面两种认证逐步集成。
|
||||
|
||||
## HTTP Basic和 HTTP Digest认证
|
||||
这两个认证是一些应用采用的比较简单的认证,目前已经有开源的第三方库支持这两个认证:
|
||||
|
||||
github.com/abbot/go-http-auth
|
||||
|
||||
下面代码演示了如何把这个库引入beego中从而实现认证:
|
||||
|
||||
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函数,在执行正常逻辑之前调用了认证函数,这样就非常简单的实现了http auth,digest的认证也是同样的原理。
|
||||
|
||||
## oauth和oauth2的认证
|
||||
oauth和oauth2是目前比较流行的两种认证方式,还好第三方有一个库实现了这个认证,但是是国外实现的,并没有QQ、微博之类的国内应用认证集成:
|
||||
|
||||
github.com/bradrydzewski/go.auth
|
||||
|
||||
下面代码演示了如何把该库引入beego中从而实现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"
|
||||
}
|
||||
|
||||
整个的流程如下,首先打开浏览器输入地址:
|
||||
|
||||

|
||||
|
||||
图14.4 显示带有登录按钮的首页
|
||||
|
||||
然后点击链接出现如下界面:
|
||||
|
||||

|
||||
|
||||
图14.5 点击登录按钮后显示github的授权页
|
||||
|
||||
然后点击Authorize app就出现如下界面:
|
||||
|
||||

|
||||
|
||||
图14.6 授权登录之后显示的获取到的github信息页
|
||||
|
||||
## 自定义认证
|
||||
自定义的认证一般都是和session结合验证的,如下代码来源于一个基于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)
|
||||
|
||||
//登录成功设置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)
|
||||
|
||||
//登录成功设置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
|
||||
}
|
||||
|
||||
## links
|
||||
* [目录](<preface.md>)
|
||||
* 上一节: [表单及验证支持](<14.3.md>)
|
||||
* 下一节: [多语言支持](<14.5.md>)
|
||||
# 14.4 User validation
|
||||
|
||||
In the process of developing Web applications, user authentication is frequently encountered problems developers, user log in, registration, log out and other operations, and the general certification is also divided into three aspects of certification
|
||||
|
||||
- HTTP Basic and HTTP Digest Authentication
|
||||
- Third Party Certified Integration: QQ, micro-blogging, watercress, OPENID, Google, GitHub, Facebook and twitter, etc.
|
||||
- Custom user log in, registration, log out, are generally based on session, cookie authentication
|
||||
|
||||
beego There is no way for any of these three forms of integration, but can make use of third party open source library to achieve the above three methods of user authentication, but the first two subsequent authentication beego be gradually integrated.
|
||||
|
||||
## HTTP basic and digest authentication
|
||||
|
||||
These two certifications are some applications using relatively simple authentication, there are already open source third-party library supports both authentication:
|
||||
|
||||
github.com/abbot/go-http-auth
|
||||
|
||||
The following code demonstrates how to use this library in order to achieve the introduction of beego Certification:
|
||||
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
The above code takes advantage of beego the prepare function in the normal logic function is called before the certification, so it is very simple to achieve a http auth, digest authentication is the same principle.
|
||||
|
||||
## OAuth and OAuth 2 certification
|
||||
|
||||
OAuth and OAuth 2 is currently more popular two authentication methods, but fortunately, there is a third-party library to achieve this certification, but it is realized abroad, and did not QQ, microblogging like domestic application certified integration:
|
||||
|
||||
github.com/bradrydzewski/go.auth
|
||||
|
||||
The following code demonstrates how to put the library in order to achieve the introduction of beego OAuth authentication, an example to demonstrate GitHub here:
|
||||
|
||||
1. Add two routes
|
||||
|
||||
beego.RegisterController("/auth/login", &controllers.GithubController{})
|
||||
beego.RegisterController("/mainpage", &controllers.PageController{})
|
||||
|
||||
2. Then we deal GithubController landing page:
|
||||
|
||||
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. treatment after successful landing pages
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
The whole process is as follows, first open your browser and enter the address:
|
||||
|
||||

|
||||
|
||||
Figure 14.4 shows the home page with a log in button
|
||||
|
||||
Then click on the link following screen appears:
|
||||
|
||||

|
||||
|
||||
Figure 14.5 is displayed after clicking the log in button authorization GitHub page
|
||||
|
||||
Then click Authorize app will appear the following interface:
|
||||
|
||||

|
||||
|
||||
Figure 14.6 is displayed after log in authorization to obtain information page GitHub
|
||||
|
||||
## Custom authentication
|
||||
|
||||
Custom authentication and session are generally a combination of proven, the following code from an open source based beego blog:
|
||||
|
||||
//Login process
|
||||
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)
|
||||
|
||||
//Set the session successful login
|
||||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
|
||||
sess.Set("uid", userInfo.Id)
|
||||
sess.Set("uname", userInfo.Username)
|
||||
|
||||
this.Ctx.Redirect(302, "/")
|
||||
}
|
||||
}
|
||||
|
||||
//Registration process
|
||||
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)
|
||||
|
||||
//Set the session successful login
|
||||
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
|
||||
}
|
||||
|
||||
With the user log in and registration, where you can add other modules such as the judgment of whether the user log in:
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
## Links
|
||||
|
||||
- [Directory](preface.md)
|
||||
- Previous section: [Form](14.3.md)
|
||||
- Next section: [Multi-language support](14.5.md)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user