From afd7caf99492c151e17b220bc5e4b086aaf245d5 Mon Sep 17 00:00:00 2001 From: maxwell Date: Tue, 8 Oct 2024 17:04:56 +0800 Subject: [PATCH] update --- config/config.go | 24 +++- main.go | 2 +- middleware/student.go | 254 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 273 insertions(+), 7 deletions(-) create mode 100644 middleware/student.go diff --git a/config/config.go b/config/config.go index 8e5db4b..6f1c6e1 100644 --- a/config/config.go +++ b/config/config.go @@ -5,16 +5,28 @@ import ( ) type Config struct { - DBConnString string - RedisAddr string - JWTSecret string + DBConnString string + RedisAddr string + JWTSecret string + APIUser string + APIPassword string + APITokenUrl string + APIUserUrl string + APIStudentUrl string + APIParentUrl string } func New() *Config { return &Config{ - DBConnString: "root:password@tcp(localhost:3306)/testfb?charset=utf8mb4&parseTime=True&loc=Local", - RedisAddr: "localhost", - JWTSecret: "your-secret-key", + DBConnString: "root:password@tcp(localhost:3306)/testfb?charset=utf8mb4&parseTime=True&loc=Local", + RedisAddr: "localhost", + JWTSecret: "your-secret-key", + APIUser: "Ekatong", + APIPassword: "kBzrhWnEArk2AJskj8", + APITokenUrl: "https://wlkj.suzhou.edu.cn/v1/api/edu/suzhou/app-user/login", + APIUserUrl: "https://wlkj.suzhou.edu.cn/v1/api/edu/suzhou/user/one/nationalId", + APIStudentUrl: "https://wlkj.suzhou.edu.cn/v1/api/edu/suzhou/student/find-by-nationalId", + APIParentUrl: "https://wlkj.suzhou.edu.cn/v1/api/edu/suzhou/student/find-by-parent", } } diff --git a/main.go b/main.go index f7c98b6..28334c1 100644 --- a/main.go +++ b/main.go @@ -55,7 +55,7 @@ func main() { app.Get("/user", middleware.AuthMiddleware(redisClient), handlers.GetCurrentUser(db)) app.Put("/user", middleware.AuthMiddleware(redisClient), handlers.UpdateCurrentUser(db)) app.Get("/users/:id", middleware.AuthMiddleware(redisClient), handlers.GetUserByID(db)) - + app.Post("/getuser", middleware.GetUserInfo(redisClient)) // Start server log.Fatal(app.Listen(":7777")) } diff --git a/middleware/student.go b/middleware/student.go new file mode 100644 index 0000000..0e7f8f6 --- /dev/null +++ b/middleware/student.go @@ -0,0 +1,254 @@ +package middleware + +import ( + "bytes" + "encoding/json" + "errors" + "io" + "net/http" + "testfb/config" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/storage/redis/v3" +) + +// POST 根据身份证和token,来获取家长或老师的基本信息 +func GetUserInfo(redisClient *redis.Storage) fiber.Handler { + return func(c *fiber.Ctx) error { + // 获取POST 请求参数 + nationalId := c.Params("nationalId") + if nationalId == "" { + return c.Status(http.StatusUnauthorized).JSON(fiber.Map{ + "message": "获取信息失败,身份证不能为空", + "error": "身份证不能为空", + }) + } + cfg := config.New() + token, err := getEKTPlatformToken(redisClient, cfg.APIUser, cfg.APIPassword) + if err != nil { + return c.Status(http.StatusUnauthorized).JSON(fiber.Map{ + "message": "获取token失败,", + "error": err.Error(), + }) + } + // 验证身份证有效性 + url := cfg.APIUserUrl + reqBody := map[string]string{ + "token": token, + "nationalId": nationalId, + } + reqBodyJson, _ := json.Marshal(reqBody) + req, err := http.Post(url, "application/json", bytes.NewBuffer(reqBodyJson)) + if err != nil { + return c.Status(http.StatusUnauthorized).JSON(fiber.Map{ + "message": "获取学生信息失败,无法解析URL", + "error": err.Error(), + }) + } + defer req.Body.Close() + body, _ := io.ReadAll(req.Body) + // 解析返回的json数据,判断是否有code字段并且code是否为1,如果是,则获取并返回token + var result map[string]interface{} + json.Unmarshal(body, &result) + if _, ok := result["code"]; !ok || result["code"] != 1 { + return c.Status(http.StatusUnauthorized).JSON(fiber.Map{ + "message": "获取学生信息失败,身份证无效", + "error": "身份证无效", + }) + } + // 如果身份正常,则返回所有信息 + return c.JSON(result) + } +} + +// 根据学生身份证和token,获取学生的基本信息 +func GetStudentInfo(redisClient *redis.Storage) fiber.Handler { + return func(c *fiber.Ctx) error { + // 获取POST 请求参数 + nationalId := c.Params("nationalId") + if nationalId == "" { + return c.Status(http.StatusUnauthorized).JSON(fiber.Map{ + "message": "获取学生信息失败,身份证不能为空", + "error": "身份证不能为空", + }) + } + cfg := config.New() + token, err := getEKTPlatformToken(redisClient, cfg.APIUser, cfg.APIPassword) + if err != nil { + return c.Status(http.StatusUnauthorized).JSON(fiber.Map{ + "message": "获取token失败,", + "error": err.Error(), + }) + } + // 验证身份证有效性 + url := cfg.APIStudentUrl + reqBody := map[string]string{ + "token": token, + "nationalId": nationalId, + } + reqBodyJson, _ := json.Marshal(reqBody) + req, err := http.Post(url, "application/json", bytes.NewBuffer(reqBodyJson)) + if err != nil { + return c.Status(http.StatusUnauthorized).JSON(fiber.Map{ + "message": "获取学生信息失败,无法解析URL", + "error": err.Error(), + }) + } + defer req.Body.Close() + body, _ := io.ReadAll(req.Body) + // 解析返回的json数据,判断是否有code字段并且code是否为1,如果是,则获取并返回token + var result map[string]interface{} + json.Unmarshal(body, &result) + if _, ok := result["code"]; !ok || result["code"] != 1 { + return c.Status(http.StatusUnauthorized).JSON(fiber.Map{ + "message": "获取学生信息失败,身份证无效", + "error": "身份证无效", + }) + } + // 如果身份正常,则返回所有信息 + return c.JSON(result) + } +} + +// 根据家长身份证或手机号、token,获取学生的基本信息,其中,家长身份证或手机号二选一,如果都不传,则返回错误信息,如果都传,则只判断身份证号 +func GetStudentInfoByParent(redisClient *redis.Storage) fiber.Handler { + return func(c *fiber.Ctx) error { + // 获取POST 请求参数 + nationalId := c.Params("nationalId") + mobile := c.Params("mobile") + if nationalId == "" && mobile == "" { + return c.Status(http.StatusUnauthorized).JSON(fiber.Map{ + "message": "获取学生信息失败,身份证或手机号不能为空", + "error": "身份证或手机号不能为空", + }) + } + cfg := config.New() + token, err := getEKTPlatformToken(redisClient, cfg.APIUser, cfg.APIPassword) + if err != nil { + return c.Status(http.StatusUnauthorized).JSON(fiber.Map{ + "message": "获取token失败,", + "error": err.Error(), + }) + } + // 验证身份证有效性 + url := cfg.APIParentUrl + var reqBody map[string]string + if nationalId != "" { + reqBody = map[string]string{ + "token": token, + "nationalId": nationalId, + } + } else if mobile != "" { + reqBody = map[string]string{ + "token": token, + "mobile": mobile, + } + } else { + return c.Status(http.StatusUnauthorized).JSON(fiber.Map{ + "message": "获取学生信息失败,身份证或手机号不能为空", + "error": "身份证或手机号不能为空", + }) + } + reqBodyJson, _ := json.Marshal(reqBody) + req, err := http.Post(url, "application/json", bytes.NewBuffer(reqBodyJson)) + if err != nil { + return c.Status(http.StatusUnauthorized).JSON(fiber.Map{ + "message": "获取学生信息失败,无法解析URL", + "error": err.Error(), + }) + } + defer req.Body.Close() + body, _ := io.ReadAll(req.Body) + // 解析返回的json数据,判断是否有code字段并且code是否为1,如果是,则获取并返回token + var result map[string]interface{} + json.Unmarshal(body, &result) + if _, ok := result["code"]; !ok || result["code"] != 1 { + return c.Status(http.StatusUnauthorized).JSON(fiber.Map{ + "message": "获取学生信息失败,身份证或手机号无效", + "error": "身份证或手机号无效", + }) + } + // 如果身份正常,则返回所有信息 + return c.JSON(result) + } +} + +// Redis中 取数据 +func getEKTPlatformToken(redisClient *redis.Storage, username string, password string) (string, error) { + userIDBytes, err := redisClient.Get("testToken") + if err != nil { + return "", errors.New("获取token失败,redis错误") + } + if userIDBytes != nil { + token := string(userIDBytes) + // 验证token有效性 + isValid, err := verifyToken(token) + if err != nil { + return "", errors.New(err.Error()) + } + if isValid { + return token, nil + } + } + // token无效,重新获取token + token, err := fetchTokenFromAPI(username, password) + if err != nil { + return "", errors.New(err.Error()) + } + redisClient.Set("testToken", []byte(token), 3600) + return token, nil +} + +func fetchTokenFromAPI(username, password string) (string, error) { + //url 定义在config.go中 + cfg := config.New() + + url := cfg.APITokenUrl + reqBody := map[string]string{ + "username": username, + "password": password, + } + reqBodyJson, _ := json.Marshal(reqBody) + returnValue, err := http.Post(url, "application/json", bytes.NewBuffer(reqBodyJson)) + if err != nil { + return "", errors.New("获取token失败") + } + defer returnValue.Body.Close() + body, _ := io.ReadAll(returnValue.Body) + // 解析返回的json数据,判断是否有code字段并且code是否为1,如果是,则获取并返回token + var result map[string]interface{} + json.Unmarshal(body, &result) + if _, ok := result["code"]; !ok || result["code"] != 1 { + return "", errors.New("获取token失败,token无效") + } + // 如果不存在message字段,或message字段的值为空,则token为空 + if _, ok := result["message"]; !ok || result["message"] == "" { + return "", errors.New("获取token失败,token为空") + } + return result["message"].(string), nil +} + +// 验证接口有效性 +func verifyToken(token string) (bool, error) { + cfg := config.New() + url := cfg.APIUserUrl + reqBody := map[string]string{ + "token": token, + "nationalId": "123", + } + reqBodyJson, _ := json.Marshal(reqBody) + req, err := http.Post(url, "application/json", bytes.NewBuffer(reqBodyJson)) + if err != nil { + return false, errors.New("验证token失败,无法解析URL") + } + defer req.Body.Close() + body, _ := io.ReadAll(req.Body) + // 解析返回的json数据,判断是否有code字段并且code是否为1,如果是,则获取并返回token + var result map[string]interface{} + json.Unmarshal(body, &result) + // 如果不存在code 字段,或者code字段的值不是1,则token无效 + if _, ok := result["code"]; !ok || result["code"] != 1 { + return false, errors.New("验证token失败,token无效") + } + return true, nil +}