当前位置:网站首页>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)
}
边栏推荐
- 精彩回顾|I/O Extended 2022 活动干货分享
- 2022-2-13 learning xiangniuke project - version control
- [point cloud processing paper crazy reading classic version 10] - pointcnn: revolution on x-transformed points
- Arbre DP acwing 285. Un bal sans patron.
- LeetCode 715. Range 模块
- Tag paste operator (#)
- C language programming specification
- Vs2019 configuration opencv3 detailed graphic tutorial and implementation of test code
- LeetCode 515. Find the maximum value in each tree row
- 【毕业季|进击的技术er】又到一年毕业季,一毕业就转行,从动物科学到程序员,10年程序员有话说
猜你喜欢
![[point cloud processing paper crazy reading classic version 14] - dynamic graph CNN for learning on point clouds](/img/7d/b66545284d6baea2763fd8d8555e1d.png)
[point cloud processing paper crazy reading classic version 14] - dynamic graph CNN for learning on point clouds

AcWing 788. 逆序对的数量

Complex character + number pyramid

AcWing 786. 第k个数
![[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

LeetCode 513. Find the value in the lower left corner of the tree

On the setting of global variable position in C language

数字化管理中台+低代码,JNPF开启企业数字化转型的新引擎

20220630 learning clock in

【点云处理之论文狂读经典版11】—— Mining Point Cloud Local Structures by Kernel Correlation and Graph Pooling
随机推荐
低代码起势,这款信息管理系统开发神器,你值得拥有!
树形DP AcWing 285. 没有上司的舞会
数字化转型中,企业设备管理会出现什么问题?JNPF或将是“最优解”
[point cloud processing paper crazy reading classic version 7] - dynamic edge conditioned filters in revolutionary neural networks on Graphs
Memory search acwing 901 skiing
2022-2-14 learning xiangniuke project - Session Management
[point cloud processing paper crazy reading classic version 12] - foldingnet: point cloud auto encoder via deep grid deformation
Slice and index of array with data type
Recommend a low code open source project of yyds
State compression DP acwing 91 Shortest Hamilton path
On February 14, 2022, learn the imitation Niuke project - develop the registration function
【点云处理之论文狂读经典版9】—— Pointwise Convolutional Neural Networks
LeetCode 324. 摆动排序 II
LeetCode 515. Find the maximum value in each tree row
我们有个共同的名字,XX工
LeetCode 324. Swing sort II
The "booster" of traditional office mode, Building OA office system, was so simple!
LeetCode 241. Design priorities for operational expressions
Common DOS commands
Vscode connect to remote server