yunzer_go/server/controllers/auth.go

271 lines
7.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package controllers
import (
"encoding/json"
"server/models"
"server/services"
"strconv"
"strings"
"time"
"github.com/beego/beego/v2/client/orm"
beego "github.com/beego/beego/v2/server/web"
)
// 用于签名的密钥
var jwtSecret = []byte("yunzer_jwt_secret_key")
// AuthController 处理认证相关请求
type AuthController struct {
beego.Controller
}
// Login 处理登录请求
func (c *AuthController) Login() {
var username, password, tenantName string
// 优先尝试从URL参数获取
username = c.GetString("username")
password = c.GetString("password")
tenantName = c.GetString("tenant_name")
// 如果URL参数为空尝试从JSON请求体获取
if username == "" || password == "" || tenantName == "" {
var loginData struct {
Username string `json:"username"`
Password string `json:"password"`
TenantName string `json:"tenant_name"`
}
err := json.Unmarshal(c.Ctx.Input.RequestBody, &loginData)
if err != nil {
c.Data["json"] = map[string]interface{}{
"code": 1,
"message": "请求参数格式错误",
"data": nil,
}
c.ServeJSON()
return
}
username = loginData.Username
password = loginData.Password
tenantName = loginData.TenantName
}
// 验证参数
if tenantName == "" {
c.Data["json"] = map[string]interface{}{
"code": 1,
"message": "租户名称不能为空",
"data": nil,
}
c.ServeJSON()
return
}
// 验证用户(先检查用户表,找不到再检查员工表)
user, employee, err := services.ValidateUser(username, password, tenantName)
if err != nil {
// 登录失败
c.Data["json"] = map[string]interface{}{
"code": 1,
"message": err.Error(),
}
} else {
var tokenString string
var userId int
var usernameForToken string
var tenantId int
var userInfo map[string]interface{}
// 判断是用户登录还是员工登录
if user != nil {
// 用户登录
userId = user.Id
usernameForToken = user.Username
tenantId = user.TenantId
userInfo = map[string]interface{}{
"id": user.Id,
"username": user.Username,
"email": user.Email,
"avatar": user.Avatar,
"nickname": user.Nickname,
"tenant_id": user.TenantId,
"role": user.Role, // 角色ID
"type": "user", // 标识是用户登录
}
} else if employee != nil {
// 员工登录
userId = employee.Id
usernameForToken = employee.EmployeeNo
tenantId = employee.TenantId
userInfo = map[string]interface{}{
"id": employee.Id,
"username": employee.EmployeeNo,
"name": employee.Name,
"email": employee.Email,
"phone": employee.Phone,
"tenant_id": employee.TenantId,
"department_id": employee.DepartmentId,
"position_id": employee.PositionId,
"role": employee.Role, // 角色ID
"type": "employee", // 标识是员工登录
}
} else {
c.Data["json"] = map[string]interface{}{
"code": 1,
"message": "登录验证失败",
}
c.ServeJSON()
return
}
// 使用models包中的GenerateToken函数生成token
userType := "user"
if employee != nil {
userType = "employee"
}
tokenString, err = models.GenerateToken(userId, usernameForToken, tenantId, userType)
if err != nil {
c.Data["json"] = map[string]interface{}{
"code": 1,
"message": "生成token失败",
"data": nil,
}
} else {
// 登录成功写当前时间到last_login_time获取IP写入last_login_ip并增加login_count
loginTime := time.Now()
// 获取客户端IP地址
clientIP := c.Ctx.Input.IP()
// 优先从X-Forwarded-For获取真实IP适用于代理环境
forwardedFor := c.Ctx.Input.Header("X-Forwarded-For")
if forwardedFor != "" {
// X-Forwarded-For可能包含多个IP取第一个
ips := strings.Split(forwardedFor, ",")
if len(ips) > 0 {
ip := strings.TrimSpace(ips[0])
// 过滤掉本地地址
if ip != "" && ip != "::1" && ip != "127.0.0.1" && !strings.HasPrefix(ip, "192.168.") && !strings.HasPrefix(ip, "10.") && !strings.HasPrefix(ip, "172.16.") {
clientIP = ip
} else if ip != "" {
clientIP = ip
}
}
}
// 如果X-Forwarded-For没有有效IP尝试从X-Real-IP获取
if clientIP == "" || clientIP == "::1" || clientIP == "127.0.0.1" {
realIP := c.Ctx.Input.Header("X-Real-IP")
if realIP != "" {
ip := strings.TrimSpace(realIP)
if ip != "::1" && ip != "127.0.0.1" {
clientIP = ip
}
}
}
// 如果获取到的是IPv6的localhost转换为IPv4格式显示
if clientIP == "::1" {
clientIP = "127.0.0.1"
}
// 如果仍然没有获取到IP使用默认值
if clientIP == "" {
clientIP = "unknown"
}
o := orm.NewOrm()
// 更新登录信息
if user != nil {
// 更新用户表
_, _ = o.Raw("UPDATE yz_users SET last_login_time = ?, last_login_ip = ?, login_count = IFNULL(login_count,0)+1 WHERE id = ?", loginTime, clientIP, user.Id).Exec()
} else if employee != nil {
// 更新员工表如果员工表有last_login_time和last_login_ip字段
// 注意:如果员工表没有这些字段,需要先添加字段
_, _ = o.Raw("UPDATE yz_tenant_employees SET last_login_time = ?, last_login_ip = ? WHERE id = ?", loginTime, clientIP, employee.Id).Exec()
}
// 记录登录操作
loginLog := &models.OperationLog{
TenantId: tenantId,
UserId: userId,
Username: usernameForToken,
Module: "auth",
ResourceType: "user",
Operation: "LOGIN",
IpAddress: clientIP,
UserAgent: c.Ctx.Input.Header("User-Agent"),
RequestMethod: "POST",
RequestUrl: c.Ctx.Input.URL(),
Status: 1,
Duration: 0,
CreateTime: loginTime,
}
_ = services.AddOperationLog(loginLog)
c.Data["json"] = map[string]interface{}{
"code": 0,
"message": "登录成功",
"data": map[string]interface{}{
"accessToken": tokenString,
"token": tokenString, // 兼容性
"user": userInfo,
},
}
}
}
c.ServeJSON()
}
// Logout 处理登出请求
func (c *AuthController) Logout() {
// 获取登出的用户信息
userIdStr := c.GetString("user_id")
username := c.GetString("username")
tenantIdStr := c.GetString("tenant_id")
var userId, tenantId int
if userIdStr != "" {
id, err := strconv.Atoi(userIdStr)
if err == nil {
userId = id
}
}
if tenantIdStr != "" {
id, err := strconv.Atoi(tenantIdStr)
if err == nil {
tenantId = id
}
}
// 记录登出操作
logoutLog := &models.OperationLog{
TenantId: tenantId,
UserId: userId,
Username: username,
Module: "auth",
ResourceType: "user",
Operation: "LOGOUT",
IpAddress: c.Ctx.Input.IP(),
UserAgent: c.Ctx.Input.Header("User-Agent"),
RequestMethod: "POST",
RequestUrl: c.Ctx.Input.URL(),
Status: 1,
Duration: 0,
CreateTime: time.Now(),
}
_ = services.AddOperationLog(logoutLog)
// 在实际应用中这里需要处理JWT或Session的清除
c.Data["json"] = map[string]interface{}{
"success": true,
"message": "登出成功",
}
c.ServeJSON()
}