Browse Source
Merge branch 'refs/heads/dhy' into dev
Merge branch 'refs/heads/dhy' into dev
# Conflicts: # link_homework/go.mod # link_homework/go.sum # link_homework/internal/cmd/cmd.go # link_homework/internal/logic/logic.go # link_homework/main.go # link_homework/manifest/config/config.yamldev_ljk
12 changed files with 371 additions and 23 deletions
-
1link_homework/api/v1/homework/login.go
-
5link_homework/go.mod
-
1link_homework/go.sum
-
25link_homework/internal/cmd/cmd.go
-
6link_homework/internal/consts/consts.go
-
56link_homework/internal/controller/auth/login.go
-
6link_homework/internal/logic/logic.go
-
76link_homework/internal/logic/login/login.go
-
43link_homework/internal/logic/middleware/JWTMiddleware.go
-
34link_homework/internal/service/login.go
-
26link_homework/main.go
-
115link_homework/utility/utility.go
@ -0,0 +1 @@ |
|||
package homework |
@ -1 +1,7 @@ |
|||
package consts |
|||
|
|||
// Redis和其他配置常量
|
|||
const ( |
|||
URL_KEY = "jingwang:cms:env" // Redis中的键
|
|||
URL_HASH_KEY = "HLJW_BASE_URL" // Redis中的hashKey
|
|||
) |
@ -0,0 +1,56 @@ |
|||
package auth |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/gogf/gf/v2/frame/g" |
|||
"github.com/gogf/gf/v2/net/ghttp" |
|||
"link_homework/internal/model/dto" |
|||
"link_homework/internal/service" |
|||
) |
|||
|
|||
type LoginController struct { |
|||
} |
|||
|
|||
func NewLoginController() *LoginController { |
|||
return &LoginController{} |
|||
} |
|||
|
|||
// 登录接口
|
|||
|
|||
func (c *LoginController) Login(r *ghttp.Request) { |
|||
var ( |
|||
username = r.Get("username").String() |
|||
password = r.Get("password").String() |
|||
) |
|||
|
|||
token, err := service.LoginLogic().Login(r.Context(), username, password) |
|||
if err != nil { |
|||
r.Response.WriteJsonExit(dto.Error(err.Error())) |
|||
} |
|||
|
|||
r.Response.WriteJsonExit(dto.SuccessWithData(g.Map{ |
|||
"token": token, |
|||
})) |
|||
} |
|||
|
|||
// 退出接口
|
|||
func (c *LoginController) Logout(r *ghttp.Request) { |
|||
// 获取请求中的 context
|
|||
ctx := r.Context() |
|||
|
|||
// 从请求头中获取 token
|
|||
token := r.Header.Get("token") |
|||
if token == "" { |
|||
r.Response.WriteJsonExit(dto.ErrorWithCode(http.StatusUnauthorized, "Token 不能为空")) |
|||
} |
|||
|
|||
// 校验 Token 是否有效
|
|||
valid, err := service.LoginLogic().ValidateToken(ctx, token) |
|||
if err != nil || !valid { |
|||
r.Response.WriteJsonExit(dto.ErrorWithCode(http.StatusUnauthorized, "Token 无效")) |
|||
} |
|||
|
|||
// 返回登出成功
|
|||
r.Response.WriteJsonExit(dto.Success()) |
|||
} |
@ -0,0 +1,76 @@ |
|||
package login |
|||
|
|||
import ( |
|||
"context" |
|||
"errors" |
|||
"time" |
|||
|
|||
"github.com/golang-jwt/jwt/v4" |
|||
"link_homework/internal/service" |
|||
) |
|||
|
|||
type sLoginLogic struct{} |
|||
|
|||
var ( |
|||
SecretKey = []byte("HomilyLink") // 用于签名和验证 JWT 的密钥
|
|||
) |
|||
|
|||
// 自定义声明结构
|
|||
type CustomClaims struct { |
|||
Username string `json:"username"` |
|||
jwt.RegisteredClaims |
|||
} |
|||
|
|||
func NewLoginLogic() *sLoginLogic { |
|||
return &sLoginLogic{} |
|||
} |
|||
|
|||
// 确保在初始化时注册该实现
|
|||
func init() { |
|||
service.RegisterLoginLogic(&sLoginLogic{}) |
|||
} |
|||
|
|||
// Login 方法实现用户登录并生成 Token
|
|||
func (l *sLoginLogic) Login(ctx context.Context, username, password string) (string, error) { |
|||
if username != "admin" || password != "12345" { |
|||
return "", errors.New("用户名或密码错误") |
|||
} |
|||
|
|||
// 创建 JWT Token
|
|||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ |
|||
"username": username, |
|||
"exp": time.Now().Add(time.Hour * 1).Unix(), // 1 小时后过期
|
|||
}) |
|||
|
|||
// 签名并获取完整的编码后的字符串 token
|
|||
tokenString, err := token.SignedString(SecretKey) |
|||
if err != nil { |
|||
return "", err |
|||
} |
|||
|
|||
return tokenString, nil |
|||
} |
|||
|
|||
// ValidateToken 验证 Token 是否有效
|
|||
func (l *sLoginLogic) ValidateToken(ctx context.Context, tokenString string) (bool, error) { |
|||
// 解析 token
|
|||
token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) { |
|||
return SecretKey, nil |
|||
}) |
|||
|
|||
if err != nil { |
|||
return false, errors.New("Token 无效: " + err.Error()) |
|||
} |
|||
|
|||
// 如果 token 有效,返回 true
|
|||
if token.Valid { |
|||
// 提取 CustomClaims 并打印 username
|
|||
//if claims, ok := token.Claims.(*CustomClaims); ok {
|
|||
// log.Printf("解析到的用户名: %s", claims.Username) // 打印解析到的用户名
|
|||
//}
|
|||
return true, nil |
|||
} |
|||
|
|||
// 如果 token 无效
|
|||
return false, errors.New("Token 验证失败") |
|||
} |
@ -0,0 +1,43 @@ |
|||
package middleware |
|||
|
|||
import ( |
|||
"link_homework/internal/logic/login" |
|||
"net/http" |
|||
"strings" |
|||
|
|||
"github.com/gogf/gf/v2/net/ghttp" |
|||
"github.com/golang-jwt/jwt/v4" |
|||
) |
|||
|
|||
// JWT 验证中间件
|
|||
func JWTMiddleware(r *ghttp.Request) { |
|||
// 从请求头中获取 token
|
|||
authHeader := r.Header.Get("Authorization") |
|||
if authHeader == "" { |
|||
r.Response.WriteStatusExit(http.StatusUnauthorized, "Authorization header missing") |
|||
} |
|||
|
|||
// 检查 token 前缀
|
|||
parts := strings.SplitN(authHeader, " ", 2) |
|||
if len(parts) != 2 || parts[0] != "Bearer" { |
|||
r.Response.WriteStatusExit(http.StatusUnauthorized, "Invalid Authorization header format") |
|||
} |
|||
|
|||
tokenString := parts[1] |
|||
|
|||
// 解析 token
|
|||
token, err := jwt.ParseWithClaims(tokenString, &login.CustomClaims{}, func(token *jwt.Token) (interface{}, error) { |
|||
return login.SecretKey, nil |
|||
}) |
|||
|
|||
if err != nil || !token.Valid { |
|||
r.Response.WriteStatusExit(http.StatusUnauthorized, "Invalid token") |
|||
} |
|||
|
|||
// 将用户信息存储在上下文中
|
|||
if claims, ok := token.Claims.(*login.CustomClaims); ok { |
|||
r.SetCtxVar("username", claims.Username) |
|||
} |
|||
|
|||
r.Middleware.Next() |
|||
} |
@ -0,0 +1,34 @@ |
|||
// ================================================================================
|
|||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
|||
// You can delete these comments if you wish manually maintain this interface file.
|
|||
// ================================================================================
|
|||
|
|||
package service |
|||
|
|||
import ( |
|||
"context" |
|||
) |
|||
|
|||
type ( |
|||
ILoginLogic interface { |
|||
// Login 方法实现用户登录并生成 Token
|
|||
Login(ctx context.Context, username string, password string) (string, error) |
|||
// ValidateToken 验证 Token 是否有效
|
|||
ValidateToken(ctx context.Context, tokenString string) (bool, error) |
|||
} |
|||
) |
|||
|
|||
var ( |
|||
localLoginLogic ILoginLogic |
|||
) |
|||
|
|||
func LoginLogic() ILoginLogic { |
|||
if localLoginLogic == nil { |
|||
panic("implement not found for interface ILoginLogic, forgot register?") |
|||
} |
|||
return localLoginLogic |
|||
} |
|||
|
|||
func RegisterLoginLogic(i ILoginLogic) { |
|||
localLoginLogic = i |
|||
} |
@ -0,0 +1,115 @@ |
|||
package utility |
|||
|
|||
import ( |
|||
"encoding/json" |
|||
"errors" |
|||
"fmt" |
|||
"github.com/gogf/gf/v2/frame/g" |
|||
"github.com/gogf/gf/v2/os/gctx" |
|||
"io/ioutil" |
|||
"link_homework/internal/consts" |
|||
"link_homework/internal/model/dto" |
|||
"net/http" |
|||
"strings" |
|||
) |
|||
|
|||
// 获取 URL
|
|||
func getUrl(key, hashKey string) *dto.Result { |
|||
ctx := gctx.New() |
|||
|
|||
// 1. 从 Redis 获取 URL
|
|||
redisUrl, err := g.Redis().Do(ctx, "HGET", key, hashKey) |
|||
if err == nil && redisUrl.String() != "" { |
|||
g.Log().Infof(ctx, "从 Redis 获取到 URL: %s", redisUrl.String()) |
|||
return dto.SuccessWithData(redisUrl.String()) |
|||
} |
|||
|
|||
// 2. 如果 Redis 中没有,查询数据库
|
|||
urlResult := selectBaseUrl(hashKey) |
|||
if urlResult.Code != 200 { |
|||
return urlResult // 数据库查询失败,返回错误
|
|||
} |
|||
url := urlResult.Data.(string) |
|||
|
|||
// 3. 将 URL 存入 Redis
|
|||
if _, err = g.Redis().Do(ctx, "HSET", key, hashKey, url); err != nil { |
|||
g.Log().Warningf(ctx, "将数据存入 Redis 失败: %v", err) |
|||
} |
|||
|
|||
g.Log().Infof(ctx, "将 URL 存入 Redis: %s", url) |
|||
return dto.SuccessWithData(url) |
|||
} |
|||
|
|||
// 查询数据库中的 URL
|
|||
func selectBaseUrl(hashKey string) *dto.Result { |
|||
ctx := gctx.New() |
|||
|
|||
// 查询数据库
|
|||
value, err := g.DB("cms").Model("env").Where("`key` = ?", hashKey).Value("value") |
|||
if err != nil { |
|||
g.Log().Errorf(ctx, "数据库查询失败, 错误: %v, key: %s", err, hashKey) |
|||
return dto.Error("数据库查询失败") |
|||
} |
|||
|
|||
if value.IsNil() || value.String() == "" { |
|||
g.Log().Errorf(ctx, "未找到对应数据, key: %s", hashKey) |
|||
return dto.Error("未找到对应数据") |
|||
} |
|||
|
|||
return dto.SuccessWithData(value.String()) |
|||
} |
|||
|
|||
// 获取 jwcode
|
|||
func GetJwcodeJSON(token string) (string, error) { |
|||
// 1. 获取基础 URL
|
|||
urlResult := getUrl(consts.URL_KEY, consts.URL_HASH_KEY) |
|||
if urlResult.Code != 200 { |
|||
return "", errors.New("获取基础 URL 失败: " + urlResult.Message) |
|||
} |
|||
baseUrl := urlResult.Data.(string) |
|||
|
|||
// 2. 拼接完整的 URL
|
|||
url := baseUrl + "/api/v2/member/info" |
|||
requestBody := strings.NewReader(`{"token":"` + token + `"}`) |
|||
|
|||
// 3. 创建 HTTP 请求
|
|||
req, err := http.NewRequest("POST", url, requestBody) |
|||
if err != nil { |
|||
return "", fmt.Errorf("HTTP 请求创建失败: %v", err) |
|||
} |
|||
req.Header.Set("Content-Type", "application/json") |
|||
|
|||
// 4. 发送请求
|
|||
client := &http.Client{} |
|||
resp, err := client.Do(req) |
|||
if err != nil { |
|||
return "", fmt.Errorf("HTTP 请求失败: %v", err) |
|||
} |
|||
defer resp.Body.Close() |
|||
|
|||
// 5. 检查 HTTP 状态码
|
|||
if resp.StatusCode != http.StatusOK { |
|||
return "", fmt.Errorf("HTTP 状态码错误: %v", resp.Status) |
|||
} |
|||
|
|||
// 6. 读取并解析响应体
|
|||
body, err := ioutil.ReadAll(resp.Body) |
|||
if err != nil { |
|||
return "", fmt.Errorf("读取响应失败: %v", err) |
|||
} |
|||
|
|||
// 7. 解析 JSON 数据
|
|||
var jsonResponse map[string]interface{} |
|||
if err = json.Unmarshal(body, &jsonResponse); err != nil { |
|||
return "", fmt.Errorf("解析 JSON 失败: %v", err) |
|||
} |
|||
|
|||
// 8. 提取并直接返回 jwcode
|
|||
if data, ok := jsonResponse["data"].(map[string]interface{}); ok { |
|||
if jwcode, exists := data["jwcode"].(string); exists { |
|||
return jwcode, nil // 直接返回 jwcode
|
|||
} |
|||
} |
|||
|
|||
return "", errors.New("响应体中没有 jwcode") |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue