package auth import ( "Cold_Logistic/internal/pkg/common/codex" "Cold_Logistic/internal/pkg/common/constant" "Cold_Logistic/internal/pkg/common/global" "Cold_Logistic/internal/pkg/common/options" "Cold_Logistic/internal/server/adapter/http/middleware" "Cold_Logistic/internal/server/application/authsrv" "Cold_Logistic/internal/server/infra/dao" "encoding/json" "fmt" "github.com/gin-gonic/gin" "github.com/skip2/go-qrcode" "gogs.baozhida.cn/Cold_Logistic_libs/pkg/contrib/core" "gogs.baozhida.cn/Cold_Logistic_libs/pkg/contrib/errors" "net/http" "net/url" ) func Register(r *gin.RouterGroup) { api := NewApi() // 小程序登录 r.POST("/auth/login", api.login) r.POST("/auth/wechatLogin", api.wechatLogin) r.POST("/auth/wechatCallback", api.wechatCallBack) r.POST("/auth/loginOut", middleware.Auth(), api.LoginOut) return } type Api struct{} func NewApi() Api { return Api{} } // login // @Tags 登录 // @BasePath /clodLogistic/app/api/v1 // @Summary 小程序登录 // @Success 200 {object} authsrv.LoginRespVo // @Param req body authsrv.LoginReqVo true "登录" // @Accept application/json // @Authorization Bearer // @Router /app/auth/login [post] func (api Api) login(c *gin.Context) { req := authsrv.LoginReqVo{} if err := c.ShouldBindJSON(&req); err != nil { core.WriteErrResponse(c, errors.WithCodeOnce(err, codex.ErrBindJSON, "")) return } err := req.Validate() if err != nil { core.WriteErrResponse(c, errors.WithCodeOnce(err, codex.ErrParamValidate, "")) return } srv := authsrv.NewAuthService(dao.NewDataStore(global.CommonConnectRepoInst.StoreDB)) var res authsrv.LoginRespVo switch req.LoginType { case constant.AccountPlatform: res, err = srv.PlatformLogin(c, req) if err != nil { core.WriteErrResponse(c, errors.WithCodeOnce(err, codex.ErrSystemSrv, "")) return } case constant.AccountApplet: res, err = srv.UserLogin(c, req) if err != nil { core.WriteErrResponse(c, errors.WithCodeOnce(err, codex.ErrSystemSrv, "")) return } } core.WriteResponse(c, nil, res) } // wechatLogin // @Tags 登录 // @BasePath /clodLogistic/app/api/v1 // @Summary 微信扫码登录 // @Success 200 {object} authsrv.LoginRespVo // @Accept application/json // @Authorization Bearer // @Router /app/auth/wechatLogin [post] func (api Api) wechatLogin(c *gin.Context) { appId := options.OptInstance.Wechat.AppId state := "" //防止跨站请求伪造攻击 增加安全性 redirectURL := url.QueryEscape(options.OptInstance.Wechat.RedirectUri) //userinfo, wechatLoginURL := fmt.Sprintf("https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&state=%s&scope=snsapi_userinfo#wechat_redirect", appId, redirectURL, state) wechatLoginURL, _ = url.QueryUnescape(wechatLoginURL) // 生成二维码 qrCode, err := qrcode.Encode(wechatLoginURL, qrcode.Medium, 256) if err != nil { // 错误处理 c.String(http.StatusInternalServerError, "Error generating QR code") return } // c.Redirect(http.StatusTemporaryRedirect, wechatLoginURL) head := map[string]string{ "Content-Type": "image/png", } // 将二维码图片作为响应返回给用户 core.WriteBytesResponse(c, nil, qrCode, head) } // wechatCallBack // @Tags 登录 // @BasePath /clodLogistic/app/api/v1 // @Summary 获取微信返回的授权码 // @Success 200 {object} authsrv.LoginRespVo // @failure 500 {string} codex.ErrSystemSrv // @Param req body authsrv.LoginReqVo true "登录" // @Accept application/json // @Authorization Bearer // @Router /app/auth/wechatCallback [post] func (api Api) wechatCallBack(c *gin.Context) { // 获取微信返回的授权码 code := c.Query("code") appId := options.OptInstance.Wechat.AppId appSecret := options.OptInstance.Wechat.AppSecret // 向微信服务器发送请求,获取access_token和openid tokenResp, err := http.Get(fmt.Sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code", appId, appSecret, code)) if err != nil { core.WriteErrResponse(c, errors.WithCodeOnce(err, codex.ErrParamValidate, "error,获取token失败")) return } // 解析响应中的access_token和openid var tokenData struct { AccessToken string `json:"access_token"` ExpiresIn int `json:"expires_in"` RefreshToken string `json:"refresh_token"` OpenID string `json:"openid"` Scope string `json:"scope"` } if err1 := json.NewDecoder(tokenResp.Body).Decode(&tokenData); err1 != nil { core.WriteErrResponse(c, errors.WithCodeOnce(err, codex.ErrParamValidate, "error,获取token失败")) return } userInfoURL := fmt.Sprintf("https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s", tokenData.AccessToken, tokenData.OpenID) userInfoResp, err := http.Get(userInfoURL) defer userInfoResp.Body.Close() if err != nil { // 错误处理 core.WriteErrResponse(c, errors.WithCodeOnce(err, codex.ErrParamValidate, "获取失败")) return } //------------------------------------ var userData struct { OpenID string `json:"openid"` Nickname string `json:"nickname"` } if err1 := json.NewDecoder(userInfoResp.Body).Decode(&userData); err1 != nil { // 错误处理 core.WriteErrResponse(c, errors.WithCodeOnce(err, codex.ErrParamValidate, "获取用户信息失败")) return } req := authsrv.LoginReqVo{ LoginType: constant.AccountApplet, Openid: userData.OpenID, NickName: userData.Nickname, } srv := authsrv.NewAuthService(dao.NewDataStore(global.CommonConnectRepoInst.StoreDB)) res, err := srv.UserLogin(c, req) if err != nil { core.WriteErrResponse(c, errors.WithCodeOnce(err, codex.ErrSystemSrv, "")) return } core.WriteResponse(c, nil, res) } // LoginOut // @Tags 登录 // @BasePath /clodLogistic/app/api/v1 // @Summary 登出 // @failure 500 {string} codex.ErrSystemSrv // @Success 200 {string} "success" // @Accept application/json // @Authorization Bearer // @Router /app/auth/loginOut [post] func (api Api) LoginOut(c *gin.Context) { srv := authsrv.NewAuthService(dao.NewDataStore(global.CommonConnectRepoInst.StoreDB)) err := srv.LoginOut(c) if err != nil { core.WriteErrResponse(c, errors.WithCodeOnce(err, codex.ErrSystemSrv, "")) return } core.WriteResponse(c, nil, "success") }