当前位置:网站首页>Beego learning - JWT realizes user login and registration
Beego learning - JWT realizes user login and registration
2022-07-03 09:14:00 【Fill your head with water】
Catalog
start-up :
bee run -gendoc=true -downdoc=true
Some notes in the article are personal understandings , May not be rigorous
Use mysql Remember to import the package if necessary :_ "github.com/go-sql-driver/mysql"
1. models package
1.1 jwt.go
// JWT : header payload signature
// json web token: header Payload Signature
const (
SecretKEY string = "JWT-Secret-Key"
DEFAULT_EXPIRE_SECONDS int = 600 // Default 10 minute
PasswordHashBytes = 16
)
// MyCustomClaims
// This struct is the payload
// This structure is the payload
type MyCustomClaims struct {
UserID int `json:"userID"`
jwt.StandardClaims
}
// JwtPayload
// This struct is the parsing of token payload
// This structure is right token Payload parsing
type JwtPayload struct {
Username string `json:"username"`
UserID int `json:"userID"`
IssuedAt int64 `json:"iat"` // Release date
ExpiresAt int64 `json:"exp"` // Expiration time
}
// GenerateToken
// @Title GenerateToken
// @Description " Generate token"
// @Param loginInfo *models.LoginRequest " Login request "
// @Param userID int " user ID"
// @Param expiredSeconds int " Expiration time "
// @return tokenString string " Encoding token"
// @return err error " error message "
func GenerateToken(loginInfo *LoginRequest, userID int, expiredSeconds int) (tokenString string, err error) {
// If the expiration time is not set , The default is DEFAULT_EXPIRE_SECONDS 600s
if expiredSeconds == 0 {
expiredSeconds = DEFAULT_EXPIRE_SECONDS
}
// Create a statement
mySigningKey := []byte(SecretKEY)
// Expiration time = current time (/s)+ expiredSeconds(/s)
expireAt := time.Now().Add(time.Second * time.Duration(expiredSeconds)).Unix()
logs.Info("Token Will expire on :", time.Unix(expireAt, 0))
user := *loginInfo
claims := MyCustomClaims{
userID,
jwt.StandardClaims{
Issuer: user.Username, // publisher
IssuedAt: time.Now().Unix(), // Release time
ExpiresAt: expireAt, // Expiration time
},
}
// Use the declaration created above Generate token
// NewWithClaims( Signature algorithm SigningMethod, Statement Claims) *Token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// Using key pairs token Signature
tokenStr, err := token.SignedString(mySigningKey)
if err != nil {
return "",
errors.New(" error : token Generate failure !")
}
return tokenStr, nil
}
// ValidateToken
// @Title ValidateToken
// @Description " verification token"
// @Param tokenString string " Encoding token"
// @return *JwtPayload "Jwt Payload parsing "
// @return error " error message "
func ValidateToken(tokenString string) (*JwtPayload, error) {
// Get the before encoding token Information
token, err := jwt.ParseWithClaims(tokenString,
&MyCustomClaims{
},
func(token *jwt.Token) (interface{
}, error) {
return []byte(SecretKEY), nil
})
// obtain payload- The content of the statement
claims, ok := token.Claims.(*MyCustomClaims)
if ok && token.Valid {
logs.Info("%v %v",
claims.UserID,
claims.StandardClaims.ExpiresAt, // Expiration time
)
logs.Info("Token Will expire on :",
time.Unix(claims.StandardClaims.ExpiresAt, 0),
)
return &JwtPayload{
Username: claims.StandardClaims.Issuer, // user name : publisher
UserID: claims.UserID,
IssuedAt: claims.StandardClaims.IssuedAt,
ExpiresAt: claims.StandardClaims.ExpiresAt,
}, nil
} else {
logs.Info(err.Error())
return nil, errors.New(" error : token Validation failed ")
}
}
// RefreshToken
// @Title RefreshToken
// @Description " to update token"
// @Param tokenString string " Encoding token"
// @return newTokenString string " Coded new token"
// @return err error " error message "
func RefreshToken(tokenString string) (newTokenString string, err error) {
// Get previous token
token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{
},
func(token *jwt.Token) (interface{
}, error) {
return []byte(SecretKEY), nil
})
// Get previous token Of payload- Statement
claims, ok := token.Claims.(*MyCustomClaims)
if !ok || !token.Valid {
return "", err
}
// Create a new declaration
mySigningKey := []byte(SecretKEY)
expireAt := time.Now().Add(time.Second * time.Duration(DEFAULT_EXPIRE_SECONDS)).Unix() //new expired
newClaims := MyCustomClaims{
claims.UserID,
jwt.StandardClaims{
Issuer: claims.StandardClaims.Issuer, //name of token issue
IssuedAt: time.Now().Unix(), //time of token issue
ExpiresAt: expireAt,
},
}
// Use new statements , Generate a new token
newToken := jwt.NewWithClaims(jwt.SigningMethodHS256, newClaims)
// Use the signature algorithm for new token To sign
tokenStr, err := newToken.SignedString(mySigningKey)
if err != nil {
return "", errors.New(" error : New new json web token Generate failure !")
}
return tokenStr, nil
}
// GenerateSalt
// @Title GenerateSalt
// @Description " Generate the user's encrypted key |generate salt"
// @return salt string " Generate the user's encrypted key "
// @return err error " error message "
func GenerateSalt() (salt string, err error) {
buf := make([]byte, PasswordHashBytes)
if _, err := io.ReadFull(rand.Reader, buf); err != nil {
return "", errors.New("error: failed to generate user's salt")
}
return fmt.Sprintf("%x", buf), nil
}
// GeneratePassHash
// @Title GenerateSalt
// @Description " Encrypt password |generate password hash"
// @Param password string " User login password "
// @Param salt string " User's encrypted key "
// @return hash string " Encrypted password "
// @return err error " error message "
func GeneratePassHash(password string, salt string) (hash string, err error) {
h, err := scrypt.Key([]byte(password), []byte(salt), 16384, 8, 1, PasswordHashBytes)
if err != nil {
return "", errors.New("error: failed to generate password hash")
}
return fmt.Sprintf("%x", h), nil
}
1.2 user.go
// TabUser Define user format
type TabUser struct {
Id int `json:"id" orm:"column(id);auto"`
UserName string `json:"username" orm:"column(username);size(128)"`
Password string `json:"password" orm:"column(password);size(128)"`
Salt string `json:"salt" orm:"column(salt);size(128)"`
}
// LoginRequest Define the login request format
type LoginRequest struct {
Username string `json:"username"`
Password string `json:"password"`
}
// LoginResponse Define login response
type LoginResponse struct {
Username string `json:"username"`
UserID int `json:"userID"`
Token string `json:"token"`
}
//CreateRequest Define the format for creating user requests
type CreateRequest struct {
Username string `json:"username"`
Password string `json:"password"`
}
//CreateResponse Define create user response
type CreateResponse struct {
UserID int `json:"userID"`
Username string `json:"username"`
}
// DoLogin
// @Title DoLogin
// @Description " The user login "
// @Param lr *LoginRequest " Login request "
// @return *LoginResponse " Login response "
// @return int " Status code "
// @return error " error message "
func DoLogin(lr *LoginRequest) (*LoginResponse, int, error) {
// Get user name and password
username := lr.Username
password := lr.Password
// Verify that the user name and password are empty
if len(username) == 0 || len(password) == 0 {
return nil,
http.StatusBadRequest,
errors.New("error: The user name or password is empty ")
}
// Connect to database
o := orm.NewOrm()
// Check if the user name exists
user := &TabUser{
UserName: username}
err := o.Read(user, "username")
if err != nil {
return nil,
http.StatusBadRequest, // 400
errors.New("error: The username does not exist ")
}
// Generate hash Encrypted password
hash, err := GeneratePassHash(password, user.Salt)
if err != nil {
return nil,
http.StatusBadRequest, // 400
err
}
// Compare passwords entered by users + Generated by the user's encryption key hash password And Stored in the database hash password
if hash != user.Password {
return nil,
http.StatusBadRequest,
errors.New(" error : Wrong password !")
}
// Generate token
tokenString, err := GenerateToken(lr, user.Id, 0)
if err != nil {
return nil,
http.StatusBadRequest,
err
}
// Generated token Back to the front end
return &LoginResponse{
Username: user.UserName,
UserID: user.Id,
Token: tokenString,
}, http.StatusOK, nil
}
// DoCreateUser
// @Title DoCreateUser
// @Description " Create user "
// @Param cr *CreateRequest " The user creates the request "
// @return *CreateResponse " User created response "
// @return int " Status code "
// @return error " error message "
func DoCreateUser(cr *CreateRequest) (*CreateResponse, int, error) {
// Connect to database
o := orm.NewOrm()
// Check if the user name exists
userNameCheck := TabUser{
UserName: cr.Username}
err := o.Read(&userNameCheck, "username")
if err == nil {
return nil, http.StatusBadRequest, errors.New("username has already existed")
}
// Generate User's encrypted key
saltKey, err := GenerateSalt()
if err != nil {
logs.Info(err.Error())
return nil, http.StatusBadRequest, err
}
// Generate hash Encrypted password
hash, err := GeneratePassHash(cr.Password, saltKey)
if err != nil {
logs.Info(err.Error())
return nil, http.StatusBadRequest, err
}
// Create user
user := TabUser{
}
user.UserName = cr.Username
user.Password = hash
user.Salt = saltKey
_, err = o.Insert(&user)
if err != nil {
logs.Info(err.Error())
return nil, http.StatusBadRequest, err
}
return &CreateResponse{
UserID: user.Id,
Username: user.UserName,
}, http.StatusOK, nil
}
// mapping mysql data
func init() {
orm.RegisterModel(new(TabUser))
}
2. controller package
2.1 user.go
// UserController Handle user related requests
// user API
type UserController struct {
beego.Controller
}
// Resolve request , And store the request body in v in
// unmarshalPayload
// @Param v interface{} true " Receive the variables of the parsed request body "
func (c *UserController) unmarshalPayload(v interface{
}) error {
// json analysis
// Unmarshal(data []byte, v interface{})
// take json The string is decoded to the corresponding data structure
err := json.Unmarshal(c.Ctx.Input.RequestBody, &v)
if err != nil {
logs.Error("RequestBody Parse failure !")
}
if err != nil {
logs.Error("unmarshal payload of %s error: %s", c.Ctx.Request.URL.Path, err)
}
return nil
}
// respond
// @Title respond
// @Description Information returned to the front end
// @Param code int true " Status code "
// @Param message string true " Return information "
// @Param data ...interface{} true " data "
func (c *UserController) respond(code int, message string, data ...interface{
}) {
c.Ctx.Output.SetStatus(code)
var d interface{
}
if len(data) > 0 {
d = data[0]
}
c.Data["json"] = struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{
} `json:"data,omitempty"`
}{
Code: code,
Message: message,
Data: d,
}
c.ServeJSON()
}
// Login
// @Title Login
// @Description Processing login requests
func (c *UserController) Login() {
lr := new(models.LoginRequest)
if err := c.unmarshalPayload(lr); err != nil {
c.respond(http.StatusBadRequest, err.Error())
return
}
lrs, statusCode, err := models.DoLogin(lr)
if err != nil {
c.respond(statusCode, err.Error())
return
}
// take token Set to Header
c.Ctx.Output.Header("Authorization", lrs.Token)
c.respond(http.StatusOK, "", lrs)
}
// CreateUser
// @Title CreateUser
// @Description New users
// @Success 200
// @router /register [post]
func (c *UserController) CreateUser() {
cu := new(models.CreateRequest)
// obtain request body
if err := c.unmarshalPayload(cu); err != nil {
c.respond(http.StatusBadRequest, err.Error())
}
createUser, statusCode, err := models.DoCreateUser(cu)
if err != nil {
c.respond(statusCode, err.Error())
return
}
c.respond(http.StatusOK, "", createUser)
}
3.routers package
3.1 router.go
func init() {
ns := beego.NewNamespace("/api",
beego.NSNamespace("/user",
beego.NSRouter("/login", &controllers.UserController{
}, "post:Login"),
beego.NSRouter("/register", &controllers.UserController{
}, "post:CreateUser"),
),
)
beego.AddNamespace(ns)
}
4. conf package
appname = Project name
httpport = 8080
runmode = dev
autorender = false
copyrequestbody = true
EnableDocs = true
sqlconn =
[mysql]
dbHost = "localhost"
dbPort = "3306"
dbUser = " user name "
dbName = " Database name "
dbPassword = " Database password "
5. main.go
func main() {
if beego.BConfig.RunMode == "dev" {
beego.BConfig.WebConfig.DirectoryIndex = true
beego.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
}
beego.Run()
}
func init() {
// mysql
dbHost := beego.AppConfig.String("dbHost")
dbPort := beego.AppConfig.String("dbPort")
dbUser := beego.AppConfig.String("dbUser")
dbPassword := beego.AppConfig.String("dbPassword")
dbName :=beego.AppConfig.String("dbName")
dsn := dbUser + ":" + dbPassword +"@tcp("+ dbHost +":"+ dbPort +")/"+ dbName +"?charset=utf8"
// Set the basic information of the database , It is equivalent to connecting to the database
_ = orm.RegisterDataBase("default","mysql",dsn,30)
// To generate table
_ = orm.RunSyncdb("default", false, true)
}
边栏推荐
- Using DLV to analyze the high CPU consumption of golang process
- excel一小时不如JNPF表单3分钟,这样做报表,领导都得点赞!
- On February 14, 2022, learn the imitation Niuke project - develop the registration function
- LeetCode 241. 为运算表达式设计优先级
- String splicing method in shell
- Method of intercepting string in shell
- AcWing 786. 第k个数
- LeetCode 532. 数组中的 k-diff 数对
- Binary tree sorting (C language, int type)
- 树形DP AcWing 285. 没有上司的舞会
猜你喜欢
![[point cloud processing paper crazy reading classic version 10] - pointcnn: revolution on x-transformed points](/img/c1/045ca010b212376dc3e5532d25c654.png)
[point cloud processing paper crazy reading classic version 10] - pointcnn: revolution on x-transformed points

状态压缩DP AcWing 291. 蒙德里安的梦想

LeetCode 535. TinyURL 的加密与解密

LeetCode 75. Color classification

LeetCode 438. 找到字符串中所有字母异位词

LeetCode 1089. 复写零

Low code momentum, this information management system development artifact, you deserve it!

The "booster" of traditional office mode, Building OA office system, was so simple!

excel一小时不如JNPF表单3分钟,这样做报表,领导都得点赞!
![[point cloud processing paper crazy reading frontier version 10] - mvtn: multi view transformation network for 3D shape recognition](/img/94/2ab1feb252dc84c2b4fcad50a0803f.png)
[point cloud processing paper crazy reading frontier version 10] - mvtn: multi view transformation network for 3D shape recognition
随机推荐
Binary tree sorting (C language, int type)
高斯消元 AcWing 883. 高斯消元解线性方程组
Introduction to the usage of getopts in shell
Tree DP acwing 285 A dance without a boss
LeetCode 324. 摆动排序 II
【毕业季|进击的技术er】又到一年毕业季,一毕业就转行,从动物科学到程序员,10年程序员有话说
求组合数 AcWing 886. 求组合数 II
LeetCode 75. Color classification
too many open files解决方案
How to check whether the disk is in guid format (GPT) or MBR format? Judge whether UEFI mode starts or legacy mode starts?
【点云处理之论文狂读经典版10】—— PointCNN: Convolution On X-Transformed Points
Find the combination number acwing 885 Find the combination number I
20220630 learning clock in
On a un nom en commun, maître XX.
Internet Protocol learning record
推荐一个 yyds 的低代码开源项目
Excel is not as good as jnpf form for 3 minutes in an hour. Leaders must praise it when making reports like this!
【点云处理之论文狂读经典版9】—— Pointwise Convolutional Neural Networks
【点云处理之论文狂读前沿版13】—— GAPNet: Graph Attention based Point Neural Network for Exploiting Local Feature
AcWing 785. 快速排序(模板)