208 lines
5.6 KiB
Go
208 lines
5.6 KiB
Go
package controllers
|
||
|
||
import (
|
||
"encoding/json"
|
||
"server/models"
|
||
"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 := models.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,
|
||
"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,
|
||
"type": "employee", // 标识是员工登录
|
||
}
|
||
} else {
|
||
c.Data["json"] = map[string]interface{}{
|
||
"code": 1,
|
||
"message": "登录验证失败",
|
||
}
|
||
c.ServeJSON()
|
||
return
|
||
}
|
||
|
||
// 使用models包中的GenerateToken函数生成token
|
||
tokenString, err = models.GenerateToken(userId, usernameForToken, tenantId)
|
||
|
||
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()
|
||
}
|
||
|
||
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() {
|
||
// 在实际应用中,这里需要处理JWT或Session的清除
|
||
c.Data["json"] = map[string]interface{}{
|
||
"success": true,
|
||
"message": "登出成功",
|
||
}
|
||
c.ServeJSON()
|
||
}
|