fix: 管理端改为账号密码登录 (#29)

This commit is contained in:
ila
2026-08-22 09:10:35 +08:00
parent 8ef60fbcd5
commit f1044b68d1
5 changed files with 253 additions and 15 deletions
+2 -13
View File
@@ -5,17 +5,16 @@ import (
"git.ilapage.cn/OPC/chorus/admin/common"
"net/http"
"git.ilapage.cn/OPC/chorus/admin/common/global"
"github.com/gin-gonic/gin"
"github.com/go-admin-team/go-admin-core/sdk"
"github.com/go-admin-team/go-admin-core/sdk/api"
"github.com/go-admin-team/go-admin-core/sdk/config"
"github.com/go-admin-team/go-admin-core/sdk/pkg"
"github.com/go-admin-team/go-admin-core/sdk/pkg/captcha"
jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
"github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
"github.com/go-admin-team/go-admin-core/sdk/pkg/response"
"github.com/mssola/user_agent"
"git.ilapage.cn/OPC/chorus/admin/common/global"
)
func PayloadFunc(data interface{}) jwt.MapClaims {
@@ -52,8 +51,7 @@ func IdentityHandler(c *gin.Context) interface{} {
// @Description LoginHandler can be used by clients to get a jwt token.
// @Description Payload needs to be json in the form of {"username": "USERNAME", "password": "PASSWORD"}.
// @Description Reply will be of the form {"token": "TOKEN"}.
// @Description dev mode:It should be noted that all fields cannot be empty, and a value of 0 can be passed in addition to the account password
// @Description 注意:开发模式:需要注意全部字段不能为空,账号密码外可以传入0值
// @Description The request requires only username and password in every application mode.
// @Tags 登陆
// @Accept application/json
// @Product application/json
@@ -84,15 +82,6 @@ func Authenticator(c *gin.Context) (interface{}, error) {
return nil, jwt.ErrMissingLoginValues
}
if config.ApplicationConfig.Mode != "dev" {
if !captcha.Verify(loginVals.UUID, loginVals.Code, true) {
username = loginVals.Username
msg = "验证码错误"
status = "1"
return nil, jwt.ErrInvalidVerificationode
}
}
sysUser, role, e := loginVals.GetUser(db)
if e == nil {
username = loginVals.Username
@@ -0,0 +1,97 @@
package handler
import (
"bytes"
"errors"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/go-admin-team/go-admin-core/sdk/config"
jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
"golang.org/x/crypto/bcrypt"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
func TestAuthenticatorAllowsPasswordOnlyInProduction(t *testing.T) {
db := loginTestDB(t)
seedLoginUser(t, db, "operator", "correct-password")
originalMode := config.ApplicationConfig.Mode
config.ApplicationConfig.Mode = "prod"
t.Cleanup(func() { config.ApplicationConfig.Mode = originalMode })
identity, err := authenticateLoginRequest(t, db, `{"username":"operator","password":"correct-password"}`)
if err != nil {
t.Fatalf("authenticate production password-only login: %v", err)
}
claims, ok := identity.(map[string]interface{})
if !ok || claims["user"] == nil || claims["role"] == nil {
t.Fatalf("unexpected authenticated identity: %#v", identity)
}
}
func TestAuthenticatorRejectsMissingAndIncorrectPassword(t *testing.T) {
db := loginTestDB(t)
seedLoginUser(t, db, "operator", "correct-password")
for _, test := range []struct {
name string
payload string
want error
}{
{name: "missing password", payload: `{"username":"operator"}`, want: jwt.ErrMissingLoginValues},
{name: "wrong password", payload: `{"username":"operator","password":"wrong-password"}`, want: jwt.ErrFailedAuthentication},
} {
t.Run(test.name, func(t *testing.T) {
_, err := authenticateLoginRequest(t, db, test.payload)
if !errors.Is(err, test.want) {
t.Fatalf("authentication error = %v, want %v", err, test.want)
}
})
}
}
func authenticateLoginRequest(t *testing.T, db *gorm.DB, payload string) (interface{}, error) {
t.Helper()
gin.SetMode(gin.TestMode)
recorder := httptest.NewRecorder()
context, _ := gin.CreateTestContext(recorder)
request := httptest.NewRequest("POST", "/api/v1/login", bytes.NewBufferString(payload))
request.Header.Set("Content-Type", "application/json")
context.Request = request
context.Set("db", db)
return Authenticator(context)
}
func loginTestDB(t *testing.T) *gorm.DB {
t.Helper()
db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=shared"), &gorm.Config{})
if err != nil {
t.Fatalf("open login test database: %v", err)
}
for _, statement := range []string{
`CREATE TABLE sys_role (role_id INTEGER PRIMARY KEY, role_name TEXT NOT NULL, status TEXT NOT NULL, role_key TEXT NOT NULL, data_scope TEXT NOT NULL, deleted_at DATETIME NULL)`,
`CREATE TABLE sys_user (user_id INTEGER PRIMARY KEY, username TEXT NOT NULL, password TEXT NOT NULL, role_id INTEGER NOT NULL, status TEXT NOT NULL, deleted_at DATETIME NULL)`,
} {
if err := db.Exec(statement).Error; err != nil {
t.Fatalf("create login test schema: %v", err)
}
}
return db
}
func seedLoginUser(t *testing.T, db *gorm.DB, username, password string) {
t.Helper()
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
t.Fatalf("hash test password: %v", err)
}
if err := db.Exec(`INSERT INTO sys_role (role_id, role_name, status, role_key, data_scope) VALUES (1, 'operator', '2', 'chorus_operator', 'all')`).Error; err != nil {
t.Fatalf("seed login role: %v", err)
}
if err := db.Exec(`INSERT INTO sys_user (user_id, username, password, role_id, status) VALUES (1, ?, ?, 1, '2')`, username, string(hash)).Error; err != nil {
t.Fatalf("seed login user: %v", err)
}
}
-2
View File
@@ -9,8 +9,6 @@ import (
type Login struct {
Username string `form:"UserName" json:"username" binding:"required"`
Password string `form:"Password" json:"password" binding:"required"`
Code string `form:"Code" json:"code" binding:"required"`
UUID string `form:"UUID" json:"uuid" binding:"required"`
}
func (u *Login) GetUser(tx *gorm.DB) (user SysUser, role SysRole, err error) {