264 lines
8.1 KiB
Markdown
264 lines
8.1 KiB
Markdown
# 14.4 User validation
|
|
|
|
In the process of developping web applications, user authentication is a problem which developers frequently encounter. User login, registration and logout, among other operations, as well as general authentication can also divided into three parts:
|
|
|
|
- HTTP Basic, and HTTP Digest Authentication
|
|
- Third Party Authentication Integration: QQ, micro-blogging, watercress, OPENID, Google, GitHub, Facebook and twitter, etc.
|
|
- Custom user login, registration, logout, are generally based on sessions and cookie authentication
|
|
|
|
Beego does not natively provide support for any of these three things, however you can easily make use of existing third party open source libraries to implement them. The first two authentication solutions are on Beego's roadmap to eventually be integrated.
|
|
|
|
## HTTP basic and digest authentication
|
|
|
|
Both HTTP basic and digest authentication are relatively simple techniques commonly used by web applications. There are already many open source third-party libraries which support these two authentication methods, such as:
|
|
|
|
github.com/abbot/go-http-auth
|
|
|
|
The following code demonstrates how to use this library to implement authentication in a Beego application:
|
|
|
|
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's `prepare()` function to perform authentication before allowing the normal flow of execution to proceed; as you can see, it's very simple to implement HTTP authentication. Digest authentication can be implemented in much the same way.
|
|
|
|
## 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)
|
|
|