当前位置:网站首页>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)
}
边栏推荐
- [point cloud processing paper crazy reading frontier version 10] - mvtn: multi view transformation network for 3D shape recognition
- State compression DP acwing 291 Mondrian's dream
- LeetCode 535. Encryption and decryption of tinyurl
- 数字化转型中,企业设备管理会出现什么问题?JNPF或将是“最优解”
- 精彩回顾|I/O Extended 2022 活动干货分享
- The method of replacing the newline character '\n' of a file with a space in the shell
- Tree DP acwing 285 A dance without a boss
- 低代码前景可期,JNPF灵活易用,用智能定义新型办公模式
- Problems in the implementation of lenet
- Vs2019 configuration opencv3 detailed graphic tutorial and implementation of test code
猜你喜欢

DOM render mount patch responsive system

【点云处理之论文狂读前沿版12】—— Adaptive Graph Convolution for Point Cloud Analysis

【点云处理之论文狂读经典版10】—— PointCNN: Convolution On X-Transformed Points
![[point cloud processing paper crazy reading classic version 12] - foldingnet: point cloud auto encoder via deep grid deformation](/img/62/edb888200e3743b03e5b39d94758f8.png)
[point cloud processing paper crazy reading classic version 12] - foldingnet: point cloud auto encoder via deep grid deformation

Pic16f648a-e/ss PIC16 8-bit microcontroller, 7KB (4kx14)
![[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

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

浅谈企业信息化建设

Instant messaging IM is the countercurrent of the progress of the times? See what jnpf says

Format - C language project sub file
随机推荐
MySQL installation and configuration (command line version)
2022-2-13 learn the imitation Niuke project - Project debugging skills
excel一小时不如JNPF表单3分钟,这样做报表,领导都得点赞!
What is the difference between sudo apt install and sudo apt -get install?
Low code momentum, this information management system development artifact, you deserve it!
LeetCode 871. Minimum refueling times
Severity code description the project file line prohibits the display of status error c2440 "initialization": unable to convert from "const char [31]" to "char *"
Complex character + number pyramid
Use of sort command in shell
LeetCode 57. Insert interval
LeetCode 508. 出现次数最多的子树元素和
With low code prospect, jnpf is flexible and easy to use, and uses intelligence to define a new office mode
【点云处理之论文狂读经典版14】—— Dynamic Graph CNN for Learning on Point Clouds
Simple use of MATLAB
Sword finger offer II 029 Sorted circular linked list
[point cloud processing paper crazy reading frontier version 8] - pointview gcn: 3D shape classification with multi view point clouds
【点云处理之论文狂读前沿版12】—— Adaptive Graph Convolution for Point Cloud Analysis
Install third-party libraries such as Jieba under Anaconda pytorch
一个优秀速开发框架是什么样的?
我們有個共同的名字,XX工