Files
huangguo_server/web/api/adminctrl/admin.go
T
2026-09-15 19:42:41 +08:00

525 lines
18 KiB
Go

package adminctrl
import (
"encoding/base32"
"encoding/json"
"fmt"
"strings"
"91porn-server/common"
"91porn-server/common/constant"
"91porn-server/common/googauth"
"91porn-server/common/log"
"91porn-server/common/stderr"
"91porn-server/models/commod"
"91porn-server/models/l/operatorlgmod"
"91porn-server/models/v/adminmod"
"91porn-server/models/v/authoritymod"
"91porn-server/web/middleware/authweb"
"91porn-server/web/service/adminser"
"91porn-server/web/service/authorser"
"github.com/gin-gonic/gin"
"github.com/skip2/go-qrcode"
"go.mongodb.org/mongo-driver/bson/primitive"
"golang.org/x/crypto/bcrypt"
)
// Login doc
// @Summary 登陆 - 管理员登陆
// @Description 管理员登陆
// @Tags web-登陆
// @Accept mpfd,json
// @Produce json,html
// @Param name formData string true "账号"
// @Param password formData string true "密码"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/login [post]
func Login(c *gin.Context) {
var arg struct {
Name string `form:"name" json:"name" binding:"required"`
Password string `form:"password" json:"password" binding:"required"`
}
if err := c.ShouldBind(&arg); err != nil {
common.ServeJSON(c, stderr.ErrParamError, "admin Login arg error: "+err.Error())
return
}
adm, err := adminmod.FindOneByName(arg.Name)
if err != nil {
common.ServeJSON(c, stderr.ErrDbQueryError, "admin Login FindOne error: "+err.Error())
return
}
if adm.Name == "" {
common.ServeJSON(c, stderr.AdminIsNotExist, "Login admin is not exist")
return
}
//校验密码
if err = bcrypt.CompareHashAndPassword([]byte(adm.Password), []byte(arg.Password)); err != nil {
common.ServeJSON(c, stderr.AdminIsNotExist, "Login admin password error")
return
}
if adm.HasLocked {
common.ServeJSON(c, stderr.AdminIsHasLockedErr, "Login admin haslocked")
return
}
var qrCodePNG []byte
if !adm.HasBind {
url := googauth.New(adm.Secret, adm.Name+"@91porn")
qrCodePNG, err = qrcode.Encode(url, qrcode.Medium, 256)
if err != nil {
common.ServeJSON(c, stderr.AdminIsNotExist, "Login GetQRCodePNG error: "+err.Error())
return
}
}
common.ServeJSON(c, stderr.Success, gin.H{
"qrCodePNG": qrCodePNG,
})
}
// SLogin doc
// @Summary 管理员sso登陆
// @Description 管理员sso登陆
// @Tags web-单点登陆
// @Accept mpfd,json
// @Produce json,html
// @Param name formData string true "账号"
// @Param password formData string true "密码"
// @Success 200 {string} json "{"msg": "管理员信息""}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/slogin [post]
func SLogin(c *gin.Context) {
var arg struct {
Name string `form:"name" json:"name" binding:"required"`
Password string `form:"password" json:"password" binding:"required"`
}
if err := c.ShouldBind(&arg); err != nil {
common.ServeJSON(c, stderr.ErrParamError, "admin SLogin arg error: "+err.Error())
return
}
adm, err := adminmod.FindOneByName(arg.Name)
if err != nil {
common.ServeJSON(c, stderr.ErrDbQueryError, "admin SLogin FindOne error: "+err.Error())
return
}
if adm.Name == "" {
common.ServeJSON(c, stderr.AdminIsNotExist, "SLogin admin is not exist")
return
}
//校验密码
if err = bcrypt.CompareHashAndPassword([]byte(adm.Password), []byte(arg.Password)); err != nil {
common.ServeJSON(c, stderr.AdminIsNotExist, "Login admin password error")
return
}
if adm.HasLocked {
common.ServeJSON(c, stderr.AdminIsHasLockedErr, "SLogin admin haslocked")
return
}
// SLogin 仅允许角色名包含"客服"的账号登录,其余角色一律拒绝
if !strings.Contains(adm.Role, "客服") {
common.ServeJSON(c, stderr.ErrAccessForbid, "SLogin 仅限客服角色登录")
return
}
var cid string
token, err := authweb.GenAndSaveToken(&authweb.Claims{Type: authweb.Admin, Act: adm.Name, Role: adm.Role, CID: cid})
if err != nil {
common.ServeJSON(c, stderr.Failure, "SLogin admin GenerateToken error: "+err.Error())
return
}
_ = adminmod.Bind(arg.Name)
authJSON, _ := authoritymod.FineOneByRole(adm.Role)
common.ServeJSON(c, stderr.Success, gin.H{
"token": token,
"authJson": authJSON.AuthJson,
"actJson": authJSON.ActJson,
"admin": adminmod.AdminDoc{
ID: &adm.ID,
Name: &adm.Name,
Role: &adm.Role,
Nickname: &adm.Nickname,
},
})
}
// Verify doc
// @Summary 管理员二步验证
// @Description 管理员二步验证
// @Tags web-登陆
// @Accept mpfd,json
// @Produce json,html
// @Param name formData string true "账号"
// @Param otp formData string true "动态口令"
// @Success 200 {string} json "{"msg": "管理员信息""}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/verify [post]
func Verify(c *gin.Context) {
var arg struct {
Name string `form:"name" json:"name" binding:"required"`
Otp string `form:"otp" json:"otp" binding:"required"`
}
if err := c.ShouldBind(&arg); err != nil {
common.ServeJSON(c, stderr.ErrParamError, "admin Verification arg error: "+err.Error())
return
}
adm, err := adminmod.FindOneByName(arg.Name)
if err != nil {
common.ServeJSON(c, stderr.ErrDbQueryError, "admin Verification FindOne error: "+err.Error())
return
}
if adm.Name == "" {
log.Error(fmt.Sprintf("用户[%v]不存在", arg.Name))
common.ServeJSON(c, stderr.ErrAccessForbid, "admin is not exist")
return
}
//测试模式不使用两步验证
// if gin.Mode() != gin.DebugMode {
// ok, err := googauth.Verify(adm.Secret, arg.Otp)
// if err != nil {
// common.ServeJSON(c, stderr.GoogleAuthFail, "admin Verification 2-step error: "+err.Error())
// return
// }
// if !ok {
// common.ServeJSON(c, stderr.GoogleAuthFail, "admin Verification 2-step verification faild")
// return
// }
// }
var cid string
if adm.Role == "裸聊商家" {
common.ServeJSON(c, stderr.GoogleAuthFail, "role faild")
return
}
token, err := authweb.GenAndSaveToken(&authweb.Claims{Type: authweb.Admin, Act: adm.Name, Role: adm.Role, CID: cid})
if err != nil {
common.ServeJSON(c, stderr.Failure, "admin GenerateToken error: "+err.Error())
return
}
_ = adminmod.Bind(arg.Name)
authJSON, _ := authoritymod.FineOneByRole(adm.Role)
common.ServeJSON(c, stderr.Success, gin.H{
"token": token,
"authJson": authJSON.AuthJson,
"actJson": authJSON.ActJson,
"admin": adminmod.AdminDoc{
ID: &adm.ID,
Name: &adm.Name,
Role: &adm.Role,
Nickname: &adm.Nickname,
},
})
}
// Logout doc
// @Summary 注销 - 管理员注销
// @Description 管理员登陆
// @Tags web-登陆
// @Accept mpfd,json
// @Produce json,html
// @Param name formData string true "账号"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/logout [post]
func Logout(c *gin.Context) {
if name, err := common.GetAdminAct(c); err == nil {
authweb.RevokeAdminToken(name)
} else {
log.Error("admin logout error", log.E(err))
}
common.ServeJSON(c, stderr.Success, "")
}
// Logout doc
// @Summary 刷新token
// @Description 刷新token
// @Tags web-登陆
// @Accept json
// @Produce json,html
// @Success 200 {string} json "{"token": "token1"}"
// @Router /web/admin/refresh [post]
func Refresh(c *gin.Context) {
name, err := common.GetAdminAct(c)
if err != nil {
common.ServeJSON(c, stderr.AdminIDErr, err)
return
}
cid, err := common.GetJuShangID(c)
if err != nil {
common.ServeJSON(c, stderr.AdminIDErr, err)
return
}
role, err := common.GetAdminRole(c)
if err != nil {
common.ServeJSON(c, stderr.AdminIDErr, err)
return
}
token, err := authweb.GenAndSaveToken(&authweb.Claims{Type: authweb.Admin, Act: name, Role: role, CID: cid})
if err != nil {
common.ServeJSON(c, stderr.AdminRefreshTokenErr, err)
return
}
common.ServeJSON(c, stderr.Success, gin.H{"token": token})
}
// Add doc
// @Summary 登陆 - 添加管理员
// @Description 添加管理员
// @Tags web-admin
// @Accept mpfd,json
// @Produce json,html
// @Param name formData string true "账号"
// @Param password formData string true "密码"
// @Param nickname formData string false "昵称"
// @Param email formData string false "邮箱"
// @Param privilegeID formData string false "权限ID"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/add [post]
func Add(c *gin.Context) {
manager, err := common.GetAdminAct(c)
if err != nil {
common.ServeJSON(c, stderr.AdminIDErr, err.Error())
return
}
var arg struct {
Name string `form:"name" json:"name" binding:"required"`
Password string `form:"password" json:"password" binding:"required"`
Nickname *string `form:"nickname" json:"nickname" binding:""` //昵称
Email *string `form:"email" json:"email" binding:"omitempty,email"` //邮箱
PrivilegeID *primitive.ObjectID `form:"privilegeID" json:"privilegeID" binding:""`
}
if err := c.ShouldBind(&arg); err != nil {
common.ServeJSON(c, stderr.ErrParamError, fmt.Errorf("auth Add arg error: %+v", err))
return
}
existed, err := adminmod.ExistsByName(arg.Name)
if err != nil {
common.ServeJSON(c, stderr.ErrParamError, fmt.Errorf("auth Add Exists error: %+v", err))
return
}
if existed {
common.ServeJSON(c, stderr.AdminIsExisted, fmt.Errorf("auth Add admin is existed"))
return
}
var role *string
if arg.PrivilegeID != nil {
auth, err := authoritymod.FindOne(authoritymod.AuthorityDoc{ID: *arg.PrivilegeID})
if err != nil {
common.ServeJSON(c, stderr.Failure, fmt.Errorf("auth FindOne error: %+v", err))
return
}
if auth.ID.IsZero() {
common.ServeJSON(c, stderr.AuthIsNotExist, gin.H{"privilegeID": arg.PrivilegeID})
return
}
role = &auth.Role
}
//生成密码
hashPwd, _ := bcrypt.GenerateFromPassword([]byte(arg.Password), bcrypt.DefaultCost)
hashPwdStr := string(hashPwd)
secret := base32.StdEncoding.EncodeToString([]byte(fmt.Sprintf("admin%s", common.RandStr(10))))
hasBind := false
if err = adminmod.Insert(nil, adminmod.AdminDoc{
Name: &arg.Name,
Password: &hashPwdStr,
Secret: &secret,
HasBind: &hasBind,
Nickname: arg.Nickname,
Email: arg.Email,
Role: role,
}); err != nil {
common.ServeJSON(c, stderr.ErrDbInsertError, fmt.Errorf("auth Add Admin.Insert error: %+v", err))
return
}
log, _ := json.Marshal(arg)
_ = operatorlgmod.RecordOperation(manager, constant.Administrator, constant.Add, string(log), c.Request.URL.RequestURI())
common.ServeJSON(c, stderr.Success, "")
}
// List doc
// @Summary 获取管理员列表
// @Description 获取管理员列表
// @Tags web-admin
// @Accept mpfd,json
// @Produce json,html
// @Param pageNumber query int true "当前页"
// @Param pageSize query int true "每页条数"
// @Param name query string false "过滤条件-管理员账号"
// @Success 200 {string} json "{"msg": "操作成功", "date": { "total":10, "list":[] }}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/list [get]
func List(c *gin.Context) {
type Query struct {
Name *string `form:"name" json:"name" bson:",omitempty"` //用户名
}
var arg struct {
commod.Page
Query
}
if err := c.ShouldBind(&arg); err != nil {
common.ServeJSON(c, stderr.ErrParamError, "admin List arg error "+err.Error())
return
}
skip := int64((arg.PageNumber - 1) * arg.PageSize)
limit := int64(arg.PageSize)
page, err := adminser.AdminPages(skip, limit, arg.Name)
if err != nil {
common.ServeJSON(c, stderr.Failure, "admin List.AdminPages error: "+err.Error())
return
}
common.ServeJSON(c, stderr.Success, page)
}
// Delete doc
// @Summary 登陆 - 删除管理员
// @Description 删除管理员
// @Tags web-admin
// @Accept mpfd,json
// @Produce json,html
// @Param adminID formData string true "目标管理员ID"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/del [delete]
func Delete(c *gin.Context) {
manager, err := common.GetAdminAct(c)
if err != nil {
common.ServeJSON(c, stderr.AdminIDErr, err.Error())
return
}
var arg struct {
AdminID string `form:"adminID" json:"adminID,omitempty" binding:"required"`
}
if err := c.ShouldBind(&arg); err != nil {
common.ServeJSON(c, stderr.ErrParamError, "author Delete arg error "+err.Error())
return
}
adminID, err := primitive.ObjectIDFromHex(arg.AdminID)
if err != nil {
common.ServeJSON(c, stderr.ErrParamError, err)
return
}
// 删除前查询账号名,用于清除token
adm, _ := adminmod.FindOneByID(adminID)
if err := adminmod.Delete(adminmod.AdminDoc{ID: &adminID}); err != nil {
common.ServeJSON(c, stderr.AdminIsNotExist, "author Delete error "+err.Error())
return
}
// 清除已删除账号的token
if adm.Name != "" {
authweb.RevokeAdminToken(adm.Name)
}
log, _ := json.Marshal(arg)
_ = operatorlgmod.RecordOperation(manager, constant.Administrator, constant.Delete, string(log), c.Request.URL.RequestURI())
common.ServeJSON(c, stderr.Success, "")
}
// Update doc
// @Summary 登陆 - 修改管理员
// @Description 修改管理员
// @Tags web-admin
// @Accept mpfd,json
// @Produce json,html
// @Param adminID formData string true "目标管理员ID"
// @Param nickname formData string false "昵称"
// @Param email formData string false "邮箱"
// @Param privilegeID formData string false "权限ID, "": 删除权限"
// @Param password formData string false "密码"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/update [post]
func Update(c *gin.Context) {
manager, err := common.GetAdminAct(c)
if err != nil {
common.ServeJSON(c, stderr.AdminIDErr, err.Error())
return
}
var arg struct {
AdminID string `form:"adminID" json:"adminID" binding:"required"`
Nickname *string `form:"nickname" json:"nickname" binding:""` //昵称
Email *string `form:"email" json:"email" binding:"omitempty,email"` //邮箱
PrivilegeID *primitive.ObjectID `form:"privilegeID" json:"privilegeID" binding:""`
Password *string `form:"password" json:"password" binding:""`
HasLocked *bool `json:"hasLocked,omitempty" form:"hasLocked"` //已禁止登陆
LockReason *string `json:"lockReason,omitempty" form:"lockReason"` //禁止登陆的原因
}
if err := c.ShouldBind(&arg); err != nil {
common.ServeJSON(c, stderr.ErrParamError, "author Update arg error "+err.Error())
return
}
adminID, err := primitive.ObjectIDFromHex(arg.AdminID)
if err != nil {
common.ServeJSON(c, stderr.ErrParamError, err)
return
}
if arg.PrivilegeID != nil {
if err := authorser.SetAuthority(adminID, *arg.PrivilegeID); err != nil {
common.ServeJSON(c, stderr.Failure, "auth SetAuthority error: "+err.Error())
return
}
}
doc := adminmod.AdminDoc{
Nickname: arg.Nickname,
Email: arg.Email,
HasLocked: arg.HasLocked,
LockReason: arg.LockReason,
}
//更新密码
if arg.Password != nil {
hashPwd, _ := bcrypt.GenerateFromPassword([]byte(*arg.Password), bcrypt.DefaultCost)
hashPwdStr := string(hashPwd)
doc.Password = &hashPwdStr
}
if err := adminmod.UpdateByID(adminID, doc); err != nil {
common.ServeJSON(c, stderr.ErrDbUpdateError, "author UpdateByID error "+err.Error())
return
}
// 禁用账号时清除token,使其立即失效
if arg.HasLocked != nil && *arg.HasLocked {
adm, _ := adminmod.FindOneByID(adminID)
if adm.Name != "" {
authweb.RevokeAdminToken(adm.Name)
}
}
log, _ := json.Marshal(arg)
_ = operatorlgmod.RecordOperation(manager, constant.Administrator, constant.Modify, string(log), c.Request.URL.RequestURI())
common.ServeJSON(c, stderr.Success, "")
}
// RefreshToken doc
// @Summary token刷新
// @Description token刷新
// @Tags web-登陆
// @Accept mpfd,json
// @Produce json,html
// @Param name formData string true "账号"
// @Param password formData string true "密码"
// @Param otp formData string true "动态口令"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /api/web/admin/channel/user/refresh [get]
func RefreshToken(c *gin.Context) {
account, err := common.GetAdminAct(c)
if err != nil {
common.ServeJSON(c, stderr.AdminIDErr, err)
return
}
role, err := common.GetAdminRole(c)
if err != nil {
common.ServeJSON(c, stderr.AdminIDErr, err)
return
}
cid, err := common.GetJuShangID(c)
if err != nil {
common.ServeJSON(c, stderr.AdminIDErr, err)
return
}
token, err := authweb.GenAndSaveToken(&authweb.Claims{Type: authweb.Admin, Act: account, Role: role, CID: cid})
if err != nil {
common.ServeJSON(c, stderr.ErrUnrecognized, "generator token error!")
return
}
c.Writer.Header().Set("Refresh-Authorization", "false")
type RefreshTokenResp struct {
Token string `json:"token"`
}
common.ServeJSON(c, stderr.Success, RefreshTokenResp{Token: token})
}