525 lines
18 KiB
Go
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})
|
|
}
|