尝试登录逻辑

This commit is contained in:
des
2026-01-19 00:07:20 +08:00
parent c61fb947e7
commit 2d65afdf33
16 changed files with 713 additions and 66 deletions

View File

@@ -0,0 +1,26 @@
package common
import (
"github.com/gin-gonic/gin"
)
type ctxKey struct {
desc string
}
var (
dataKey = ctxKey{"响应体内容"}
)
// SetData 设置响应数据,可以设置为 nil或者干脆不设置。此时会返回空的响应包装。
func SetData(c *gin.Context, data any) {
c.Set(dataKey, data)
}
// GetData 获取响应数据
// 除了响应包装器,你不应该在任何地方调用该方法。因为响应数据的类型不一。
// 如果你真的对响应数据处理。请在中间件向上下文中塞入数据,在 handler 中处理好。
func GetData(c *gin.Context) any {
data, _ := c.Get(dataKey)
return data
}

27
srv/internal/ero/error.go Normal file
View File

@@ -0,0 +1,27 @@
package ero
import "net/http"
type Type int
const (
// ServerError 通用的,不需要特殊处理暴露给前端的错误
ServerError Type = iota
// FormError 表单校验异常没有执行成功。Data 内会有明确的字段级错误返回给前端处理
FormError
)
// GeneralError 通用的错误数据包装
type GeneralError struct {
Status int
// Type 错误类型,参考自定义类型 Type
Type Type
// Message 当前错误的简短解释
Message string
// Data 如果是复杂错误,此处会返回前端协助前端展示错误的数据
Data any
}
func SimpleError(msg string) *GeneralError {
return &GeneralError{http.StatusInternalServerError, ServerError, msg, nil}
}

View File

@@ -1,7 +0,0 @@
package middle
import "github.com/gin-gonic/gin"
func SetContextError(ctx *gin.Context) {
}

View File

@@ -0,0 +1,25 @@
package middle
import (
"Crimson-Gatekeeper/internal/common"
"Crimson-Gatekeeper/internal/ero"
"github.com/gin-gonic/gin"
)
// GeneralResponse 通用的返回包装结构体。不管错误与否
type GeneralResponse struct {
success string
data any
}
// ResponsePackageMiddle 返回包装中间件
func ResponsePackageMiddle(c *gin.Context) {
c.Next()
data := common.GetData(c)
if data, ok := data.(ero.GeneralError); ok {
c.JSON(200, &GeneralResponse{"false", data})
} else {
c.JSON(200, &GeneralResponse{"fail", data})
}
}

View File

@@ -0,0 +1,26 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import (
"time"
)
const TableNameUser = "users"
// User mapped from table <users>
type User struct {
ID int64 `gorm:"column:id;primaryKey;comment:用户ID" json:"id"` // 用户ID
CreateTime time.Time `gorm:"column:create_time;not null" json:"create_time"`
LastUpdateTime time.Time `gorm:"column:last_update_time;not null" json:"last_update_time"`
Name string `gorm:"column:name;not null;comment:用户在系统内的名称" json:"name"` // 用户在系统内的名称
Account string `gorm:"column:account;not null;comment:用户登录凭证" json:"account"` // 用户登录凭证
Passwd string `gorm:"column:passwd;not null;comment:用户登录密钥" json:"passwd"` // 用户登录密钥
}
// TableName User's table name
func (*User) TableName() string {
return TableNameUser
}

103
srv/internal/query/gen.go Normal file
View File

@@ -0,0 +1,103 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"database/sql"
"gorm.io/gorm"
"gorm.io/gen"
"gorm.io/plugin/dbresolver"
)
var (
Q = new(Query)
User *user
)
func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
*Q = *Use(db, opts...)
User = &Q.User
}
func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
return &Query{
db: db,
User: newUser(db, opts...),
}
}
type Query struct {
db *gorm.DB
User user
}
func (q *Query) Available() bool { return q.db != nil }
func (q *Query) clone(db *gorm.DB) *Query {
return &Query{
db: db,
User: q.User.clone(db),
}
}
func (q *Query) ReadDB() *Query {
return q.ReplaceDB(q.db.Clauses(dbresolver.Read))
}
func (q *Query) WriteDB() *Query {
return q.ReplaceDB(q.db.Clauses(dbresolver.Write))
}
func (q *Query) ReplaceDB(db *gorm.DB) *Query {
return &Query{
db: db,
User: q.User.replaceDB(db),
}
}
type queryCtx struct {
User *userDo
}
func (q *Query) WithContext(ctx context.Context) *queryCtx {
return &queryCtx{
User: q.User.WithContext(ctx),
}
}
func (q *Query) Transaction(fc func(tx *Query) error, opts ...*sql.TxOptions) error {
return q.db.Transaction(func(tx *gorm.DB) error { return fc(q.clone(tx)) }, opts...)
}
func (q *Query) Begin(opts ...*sql.TxOptions) *QueryTx {
tx := q.db.Begin(opts...)
return &QueryTx{Query: q.clone(tx), Error: tx.Error}
}
type QueryTx struct {
*Query
Error error
}
func (q *QueryTx) Commit() error {
return q.db.Commit().Error
}
func (q *QueryTx) Rollback() error {
return q.db.Rollback().Error
}
func (q *QueryTx) SavePoint(name string) error {
return q.db.SavePoint(name).Error
}
func (q *QueryTx) RollbackTo(name string) error {
return q.db.RollbackTo(name).Error
}

View File

@@ -0,0 +1,347 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"Crimson-Gatekeeper/internal/model"
)
func newUser(db *gorm.DB, opts ...gen.DOOption) user {
_user := user{}
_user.userDo.UseDB(db, opts...)
_user.userDo.UseModel(&model.User{})
tableName := _user.userDo.TableName()
_user.ALL = field.NewAsterisk(tableName)
_user.ID = field.NewInt64(tableName, "id")
_user.CreateTime = field.NewTime(tableName, "create_time")
_user.LastUpdateTime = field.NewTime(tableName, "last_update_time")
_user.Name = field.NewString(tableName, "name")
_user.Account = field.NewString(tableName, "account")
_user.Passwd = field.NewString(tableName, "passwd")
_user.fillFieldMap()
return _user
}
type user struct {
userDo userDo
ALL field.Asterisk
ID field.Int64 // 用户ID
CreateTime field.Time
LastUpdateTime field.Time
Name field.String // 用户在系统内的名称
Account field.String // 用户登录凭证
Passwd field.String // 用户登录密钥
fieldMap map[string]field.Expr
}
func (u user) Table(newTableName string) *user {
u.userDo.UseTable(newTableName)
return u.updateTableName(newTableName)
}
func (u user) As(alias string) *user {
u.userDo.DO = *(u.userDo.As(alias).(*gen.DO))
return u.updateTableName(alias)
}
func (u *user) updateTableName(table string) *user {
u.ALL = field.NewAsterisk(table)
u.ID = field.NewInt64(table, "id")
u.CreateTime = field.NewTime(table, "create_time")
u.LastUpdateTime = field.NewTime(table, "last_update_time")
u.Name = field.NewString(table, "name")
u.Account = field.NewString(table, "account")
u.Passwd = field.NewString(table, "passwd")
u.fillFieldMap()
return u
}
func (u *user) WithContext(ctx context.Context) *userDo { return u.userDo.WithContext(ctx) }
func (u user) TableName() string { return u.userDo.TableName() }
func (u user) Alias() string { return u.userDo.Alias() }
func (u user) Columns(cols ...field.Expr) gen.Columns { return u.userDo.Columns(cols...) }
func (u *user) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := u.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (u *user) fillFieldMap() {
u.fieldMap = make(map[string]field.Expr, 6)
u.fieldMap["id"] = u.ID
u.fieldMap["create_time"] = u.CreateTime
u.fieldMap["last_update_time"] = u.LastUpdateTime
u.fieldMap["name"] = u.Name
u.fieldMap["account"] = u.Account
u.fieldMap["passwd"] = u.Passwd
}
func (u user) clone(db *gorm.DB) user {
u.userDo.ReplaceConnPool(db.Statement.ConnPool)
return u
}
func (u user) replaceDB(db *gorm.DB) user {
u.userDo.ReplaceDB(db)
return u
}
type userDo struct{ gen.DO }
func (u userDo) Debug() *userDo {
return u.withDO(u.DO.Debug())
}
func (u userDo) WithContext(ctx context.Context) *userDo {
return u.withDO(u.DO.WithContext(ctx))
}
func (u userDo) ReadDB() *userDo {
return u.Clauses(dbresolver.Read)
}
func (u userDo) WriteDB() *userDo {
return u.Clauses(dbresolver.Write)
}
func (u userDo) Session(config *gorm.Session) *userDo {
return u.withDO(u.DO.Session(config))
}
func (u userDo) Clauses(conds ...clause.Expression) *userDo {
return u.withDO(u.DO.Clauses(conds...))
}
func (u userDo) Returning(value interface{}, columns ...string) *userDo {
return u.withDO(u.DO.Returning(value, columns...))
}
func (u userDo) Not(conds ...gen.Condition) *userDo {
return u.withDO(u.DO.Not(conds...))
}
func (u userDo) Or(conds ...gen.Condition) *userDo {
return u.withDO(u.DO.Or(conds...))
}
func (u userDo) Select(conds ...field.Expr) *userDo {
return u.withDO(u.DO.Select(conds...))
}
func (u userDo) Where(conds ...gen.Condition) *userDo {
return u.withDO(u.DO.Where(conds...))
}
func (u userDo) Order(conds ...field.Expr) *userDo {
return u.withDO(u.DO.Order(conds...))
}
func (u userDo) Distinct(cols ...field.Expr) *userDo {
return u.withDO(u.DO.Distinct(cols...))
}
func (u userDo) Omit(cols ...field.Expr) *userDo {
return u.withDO(u.DO.Omit(cols...))
}
func (u userDo) Join(table schema.Tabler, on ...field.Expr) *userDo {
return u.withDO(u.DO.Join(table, on...))
}
func (u userDo) LeftJoin(table schema.Tabler, on ...field.Expr) *userDo {
return u.withDO(u.DO.LeftJoin(table, on...))
}
func (u userDo) RightJoin(table schema.Tabler, on ...field.Expr) *userDo {
return u.withDO(u.DO.RightJoin(table, on...))
}
func (u userDo) Group(cols ...field.Expr) *userDo {
return u.withDO(u.DO.Group(cols...))
}
func (u userDo) Having(conds ...gen.Condition) *userDo {
return u.withDO(u.DO.Having(conds...))
}
func (u userDo) Limit(limit int) *userDo {
return u.withDO(u.DO.Limit(limit))
}
func (u userDo) Offset(offset int) *userDo {
return u.withDO(u.DO.Offset(offset))
}
func (u userDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *userDo {
return u.withDO(u.DO.Scopes(funcs...))
}
func (u userDo) Unscoped() *userDo {
return u.withDO(u.DO.Unscoped())
}
func (u userDo) Create(values ...*model.User) error {
if len(values) == 0 {
return nil
}
return u.DO.Create(values)
}
func (u userDo) CreateInBatches(values []*model.User, batchSize int) error {
return u.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (u userDo) Save(values ...*model.User) error {
if len(values) == 0 {
return nil
}
return u.DO.Save(values)
}
func (u userDo) First() (*model.User, error) {
if result, err := u.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.User), nil
}
}
func (u userDo) Take() (*model.User, error) {
if result, err := u.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.User), nil
}
}
func (u userDo) Last() (*model.User, error) {
if result, err := u.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.User), nil
}
}
func (u userDo) Find() ([]*model.User, error) {
result, err := u.DO.Find()
return result.([]*model.User), err
}
func (u userDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.User, err error) {
buf := make([]*model.User, 0, batchSize)
err = u.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (u userDo) FindInBatches(result *[]*model.User, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return u.DO.FindInBatches(result, batchSize, fc)
}
func (u userDo) Attrs(attrs ...field.AssignExpr) *userDo {
return u.withDO(u.DO.Attrs(attrs...))
}
func (u userDo) Assign(attrs ...field.AssignExpr) *userDo {
return u.withDO(u.DO.Assign(attrs...))
}
func (u userDo) Joins(fields ...field.RelationField) *userDo {
for _, _f := range fields {
u = *u.withDO(u.DO.Joins(_f))
}
return &u
}
func (u userDo) Preload(fields ...field.RelationField) *userDo {
for _, _f := range fields {
u = *u.withDO(u.DO.Preload(_f))
}
return &u
}
func (u userDo) FirstOrInit() (*model.User, error) {
if result, err := u.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.User), nil
}
}
func (u userDo) FirstOrCreate() (*model.User, error) {
if result, err := u.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.User), nil
}
}
func (u userDo) FindByPage(offset int, limit int) (result []*model.User, count int64, err error) {
result, err = u.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = u.Offset(-1).Limit(-1).Count()
return
}
func (u userDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = u.Count()
if err != nil {
return
}
err = u.Offset(offset).Limit(limit).Scan(result)
return
}
func (u userDo) Scan(result interface{}) (err error) {
return u.DO.Scan(result)
}
func (u userDo) Delete(models ...*model.User) (result gen.ResultInfo, err error) {
return u.DO.Delete(models)
}
func (u *userDo) withDO(do gen.Dao) *userDo {
u.DO = *do.(*gen.DO)
return u
}

View File

@@ -1,50 +1,52 @@
package user
import (
"Crimson-Gatekeeper/internal/common"
"Crimson-Gatekeeper/internal/ero"
"Crimson-Gatekeeper/internal/query"
"context"
"errors"
"fmt"
"net/http"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
const version = "/api/v1"
const group = "/user"
type Controller struct {
client *gorm.DB
query *query.Query
}
type PostLoginParam struct {
type postLoginParam struct {
Account string `json:"account" binding:"required"`
Password string `json:"password" binding:"required"`
}
func (c *Controller) PostLogin(ctx *gin.Context) {
param := &PostLoginParam{}
func (c *Controller) postLogin(ctx *gin.Context) {
param := &postLoginParam{}
if err := ctx.ShouldBindJSON(&param); err != nil {
fmt.Println("参数解析失败,请确认参数是否为 JSON")
fmt.Println(err)
}
user, err := gorm.G[User](c.client).Where("account = ?", param.Account).First(context.Background())
if errors.Is(err, gorm.ErrRecordNotFound) {
fmt.Println("没有找到用户")
} else {
u := c.query.User
user, err := u.WithContext(context.Background()).Where(u.Account.Eq(param.Account)).Take()
if err != nil {
fmt.Println("查询错误")
panic(err)
common.SetData(ctx, ero.SimpleError("服务器繁忙,请稍后重试"))
}
if user == nil {
fmt.Println("没有找到用户")
return
}
if user.Passwd != param.Password {
fmt.Println("用户密码错误")
return
}
fmt.Println("接受参数")
fmt.Println(user)
ctx.JSON(http.StatusOK, gin.H{
"message": "success",
})
}
func (c *Controller) RegisterRoute(gin *gin.Engine) {
group := gin.Group(version).Group(group)
group.POST("/login", c.PostLogin)
group.POST("/login", c.postLogin)
}
// New 获取用户模块的控制器
@@ -54,6 +56,6 @@ func (c *Controller) RegisterRoute(gin *gin.Engine) {
//
// 返回值
// - Controller 控制器的实例指针
func New(client *gorm.DB) *Controller {
return &Controller{client}
func New(param *query.Query) *Controller {
return &Controller{param}
}

View File

@@ -2,6 +2,7 @@ package user_test
import (
"Crimson-Gatekeeper/internal/common"
"Crimson-Gatekeeper/internal/query"
"Crimson-Gatekeeper/internal/user"
"bytes"
"encoding/json"
@@ -14,16 +15,14 @@ import (
)
func TestLogin(t *testing.T) {
client, close := common.GetDataBaseClient()
defer close()
client, clean := common.GetDataBaseClient()
defer clean()
gin.SetMode(gin.TestMode)
app := gin.Default()
user.New(client).RegisterRoute(app)
user.New(query.Use(client)).RegisterRoute(app)
w := httptest.NewRecorder()
param := gin.H{
"account": "admin",
"account": "admin1",
"password": "123445",
}
data, ero := json.Marshal(param)

View File

@@ -1,14 +0,0 @@
package user
import (
"time"
)
type User struct {
Id int64
CreateTime time.Time
LastUpdateTime time.Time
Name string
Account string
Passwd string
}

View File

@@ -0,0 +1,25 @@
package user
import (
"Crimson-Gatekeeper/internal/model"
"Crimson-Gatekeeper/internal/query"
"sync"
"time"
)
// loginInfo 储存用户的登录状态
type loginInfo struct {
// user 信息指针
user *model.User
// invalidation 失效时间,此事件之后,该数据应该失效且被删除
invalidation time.Time
}
var loginIn = sync.Map{}
type Service struct {
c *query.Query
}
func (s *Service) login(user *model.User) error {
}