作者 tangxuhui

添加 web 端登录 和获取登录用二维码

@@ -9,6 +9,6 @@ require ( @@ -9,6 +9,6 @@ require (
9 github.com/go-pg/pg/v10 v10.10.1 9 github.com/go-pg/pg/v10 v10.10.1
10 github.com/go-redis/redis v6.14.2+incompatible 10 github.com/go-redis/redis v6.14.2+incompatible
11 github.com/linmadan/egglib-go v0.0.0-20210527091316-06b0732fb5f6 11 github.com/linmadan/egglib-go v0.0.0-20210527091316-06b0732fb5f6
12 - github.com/sony/sonyflake v1.0.0 12 + github.com/satori/go.uuid v1.2.0 // indirect
13 13
14 ) 14 )
  1 +package command
  2 +
  3 +import (
  4 + "fmt"
  5 +
  6 + "github.com/beego/beego/v2/core/validation"
  7 +)
  8 +
  9 +type LoginCommand struct {
  10 + Phone string `json:"phone" valid:"Required"`
  11 + GrantType string `json:"grantType" valid:"Required"` //登录方式(signInPassword 密码登录、signInCaptcha 验证码登录)
  12 + Password string `json:"password"`
  13 + Captcha string `json:"captcha"`
  14 +}
  15 +
  16 +func (orgAddCommand *LoginCommand) Valid(validation *validation.Validation) {
  17 +
  18 +}
  19 +
  20 +func (orgAddCommand *LoginCommand) ValidateCommand() error {
  21 + valid := validation.Validation{}
  22 + b, err := valid.Valid(orgAddCommand)
  23 + if err != nil {
  24 + return err
  25 + }
  26 + if !b {
  27 + for _, validErr := range valid.Errors {
  28 + return fmt.Errorf("%s %s", validErr.Key, validErr.Message)
  29 + }
  30 + }
  31 + return nil
  32 +}
  1 +package dto
  2 +
  3 +type CompanyItem struct {
  4 + CompanyId int `json:"companyId,string"`
  5 + CompanyName string `json:"companyName"`
  6 +}
  7 +
  8 +type OrgItem struct {
  9 + OrganizationId int `json:"organizationId,string"`
  10 + OrganizationName string `json:"organizationName"`
  11 + CompanyId int `json:"companyId"`
  12 +}
  1 +package query
  2 +
  3 +import (
  4 + "fmt"
  5 +
  6 + "github.com/beego/beego/v2/core/validation"
  7 + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-gateway/pkg/domain"
  8 +)
  9 +
  10 +type GetCompanyOrgsByUserQuery struct {
  11 + //操作人
  12 + Operator domain.Operator `json:"-"`
  13 + Phone string `json:"phone" valid:"Required"` //手机号
  14 +}
  15 +
  16 +func (orgAddCommand *GetCompanyOrgsByUserQuery) Valid(validation *validation.Validation) {
  17 +
  18 +}
  19 +
  20 +func (orgAddCommand *GetCompanyOrgsByUserQuery) ValidateCommand() error {
  21 + valid := validation.Validation{}
  22 + b, err := valid.Valid(orgAddCommand)
  23 + if err != nil {
  24 + return err
  25 + }
  26 + if !b {
  27 + for _, validErr := range valid.Errors {
  28 + return fmt.Errorf("%s %s", validErr.Key, validErr.Message)
  29 + }
  30 + }
  31 + return nil
  32 +}
  1 +package query
  2 +
  3 +type QrcodeLoginStatusQuery struct {
  4 + Token string `json:"token"`
  5 +}
  1 +package service
  2 +
  3 +import (
  4 + "errors"
  5 +
  6 + "github.com/linmadan/egglib-go/core/application"
  7 + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-gateway/pkg/application/web/auth/command"
  8 + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-gateway/pkg/application/web/auth/dto"
  9 + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-gateway/pkg/application/web/auth/query"
  10 + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-gateway/pkg/domain"
  11 + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-gateway/pkg/infrastructure/cache"
  12 + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-gateway/pkg/infrastructure/service_gateway/allied_creation_user"
  13 + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-gateway/pkg/infrastructure/service_gateway/sms_serve"
  14 +)
  15 +
  16 +type AuthService struct{}
  17 +
  18 +//AuthLogin 用户登录
  19 +func (srv AuthService) AuthLogin(loginCommand *command.LoginCommand) (interface{}, error) {
  20 + var (
  21 + result interface{}
  22 + err error
  23 + )
  24 + switch loginCommand.GrantType {
  25 + case "signInPassword":
  26 + //账号密码登录
  27 + result, err = srv.SignInPassword(loginCommand.Phone, loginCommand.Password)
  28 + case "signInCaptcha":
  29 + //手机验证码登录
  30 + result, err = srv.SignInCaptcha(loginCommand.Phone, loginCommand.Captcha)
  31 + default:
  32 + err = errors.New("登录方式无法解析")
  33 + }
  34 + return result, err
  35 +}
  36 +
  37 +//SignInPassword 使用账号密码校验
  38 +func (srv AuthService) SignInPassword(account string, password string) (interface{}, error) {
  39 + creationUserGateway := allied_creation_user.NewHttplibAlliedCreationUser(domain.Operator{})
  40 + _, err := creationUserGateway.AuthCheckPassword(allied_creation_user.ReqAuthCheckPassword{
  41 + Password: password,
  42 + Phone: account,
  43 + })
  44 + if err != nil {
  45 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  46 + }
  47 + ltoken := domain.LoginToken{
  48 + UserId: 0,
  49 + Account: account,
  50 + Platform: domain.LoginPlatformApp,
  51 + CompanyId: 0,
  52 + }
  53 + authcode, err := ltoken.GenerateAuthCode()
  54 + if err != nil {
  55 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  56 + }
  57 + result := map[string]string{
  58 + "authCode": authcode,
  59 + }
  60 + return result, nil
  61 +}
  62 +
  63 +//SignInCaptcha 使用手机验证码登录
  64 +func (srv AuthService) SignInCaptcha(phone string, captcha string) (interface{}, error) {
  65 + smsServeGateway := sms_serve.NewHttplibHttplibSmsServe()
  66 + err := smsServeGateway.CheckSmsCode(phone, captcha)
  67 + if err != nil {
  68 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  69 + }
  70 + ltoken := domain.LoginToken{
  71 + UserId: 0,
  72 + Account: phone,
  73 + Platform: domain.LoginPlatformApp,
  74 + CompanyId: 0,
  75 + }
  76 + authcode, err := ltoken.GenerateAuthCode()
  77 + if err != nil {
  78 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  79 + }
  80 + result := map[string]string{
  81 + "authCode": authcode,
  82 + }
  83 + return result, nil
  84 +}
  85 +
  86 +//GetCompanyOrgsByUser 获取登录用户的公司组织列表
  87 +func (srv AuthService) GetCompanyOrgsByUser(queryParam query.GetCompanyOrgsByUserQuery) (interface{}, error) {
  88 +
  89 + creationUserGateway := allied_creation_user.NewHttplibAlliedCreationUser(queryParam.Operator)
  90 + result, err := creationUserGateway.UserSearch(allied_creation_user.ReqUserSearch{
  91 + Phone: queryParam.Phone,
  92 + })
  93 + if err != nil {
  94 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  95 + }
  96 + var (
  97 + companys []dto.CompanyItem
  98 + orgs []dto.OrgItem
  99 + )
  100 +
  101 + for _, v := range result.Users {
  102 + companys = append(companys, dto.CompanyItem{
  103 + CompanyId: v.Company.CompanyId,
  104 + CompanyName: v.Company.CompanyName,
  105 + })
  106 + for _, vv := range v.UserOrg {
  107 + orgs = append(orgs, dto.OrgItem{
  108 + OrganizationId: vv.OrgID,
  109 + OrganizationName: vv.OrgName,
  110 + CompanyId: v.Company.CompanyId,
  111 + })
  112 + }
  113 + }
  114 +
  115 + data := map[string]interface{}{
  116 + "companys": companys,
  117 + "organizations": orgs,
  118 + }
  119 + return data, nil
  120 +}
  121 +
  122 +//GetQrcode 获取扫码登录需要的二维码
  123 +func (srv AuthService) GetQrcode() (interface{}, error) {
  124 + qrmsg := domain.QrcodeMessage{}
  125 + imgBase64, err := qrmsg.GenerateImageBase64()
  126 + if err != nil {
  127 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  128 + }
  129 + qrCache := cache.LoginQrcodeCache{}
  130 + err = qrCache.Save(qrmsg)
  131 + if err != nil {
  132 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  133 + }
  134 + data := map[string]interface{}{
  135 + "image": imgBase64,
  136 + "token": qrmsg.Token,
  137 + }
  138 + return data, nil
  139 +}
  140 +
  141 +//QrcodeLoginStatus 扫码登录状态
  142 +func (srv AuthService) QrcodeLoginStatus(queryParam query.QrcodeLoginStatusQuery) (interface{}, error) {
  143 + qrmsg := domain.QrcodeMessage{}
  144 + err := qrmsg.ParseToken(queryParam.Token)
  145 + if err != nil {
  146 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  147 + }
  148 + qrCache := cache.LoginQrcodeCache{}
  149 + qrmsgCache, err := qrCache.Get(qrmsg.Id)
  150 + if err != nil {
  151 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  152 + }
  153 + data := map[string]interface{}{
  154 + "isLogin": qrmsgCache.IsLogin,
  155 + }
  156 + return data, nil
  157 +}
  1 +package domain
  2 +
  3 +import (
  4 + "bytes"
  5 + "encoding/base64"
  6 + "fmt"
  7 + "image/png"
  8 + "time"
  9 +
  10 + "github.com/boombuler/barcode"
  11 + "github.com/boombuler/barcode/qr"
  12 + jwt "github.com/dgrijalva/jwt-go"
  13 +)
  14 +
  15 +const (
  16 + qrcodeTokenSecret string = "bbe35ad433dd8e67"
  17 + qrcodeCodeExpire int64 = 60 * 30 //15分钟过期
  18 +)
  19 +
  20 +type QrcodeMessage struct {
  21 + jwt.StandardClaims
  22 + Id string `json:"id"`
  23 + Token string `json:"token"`
  24 + IsLogin bool `json:"isLogin"`
  25 + //用户id
  26 + UserId int64 `json:"userId"`
  27 + UserBaseId int64 `json:"userBaseId"`
  28 + // 账号
  29 + Account string `json:"account"`
  30 + // 公司id
  31 + CompanyId int64 `json:"companyId"`
  32 + // 组织id
  33 + OrgId int64 `json:"orgId"`
  34 +}
  35 +
  36 +func (qrmsg *QrcodeMessage) GenerateImageBase64() ([]byte, error) {
  37 + nowTime := time.Now().Unix()
  38 + qrmsg.StandardClaims = jwt.StandardClaims{
  39 + NotBefore: nowTime,
  40 + IssuedAt: nowTime,
  41 + ExpiresAt: nowTime + qrcodeCodeExpire,
  42 + Issuer: "allied_creation_gateway",
  43 + }
  44 + qrmsg.Id = fmt.Sprintf("%d", time.Now().UnixNano())
  45 + token := jwt.NewWithClaims(jwt.SigningMethodHS256, *qrmsg)
  46 + str, err := token.SignedString([]byte(qrcodeTokenSecret))
  47 + if err != nil {
  48 + return nil, err
  49 + }
  50 + //初始化数据
  51 + qrmsg.Token = str
  52 + qrmsg.IsLogin = false
  53 +
  54 + qrCode, err := qr.Encode(str, qr.M, qr.Auto)
  55 + if err != nil {
  56 + return nil, err
  57 + }
  58 + qrCode, err = barcode.Scale(qrCode, 200, 200)
  59 + if err != nil {
  60 + return nil, err
  61 + }
  62 + var buf bytes.Buffer
  63 + err = png.Encode(&buf, qrCode)
  64 + if err != nil {
  65 + return nil, err
  66 + }
  67 + var result []byte
  68 + base64.StdEncoding.Encode(result, buf.Bytes())
  69 + return result, err
  70 +}
  71 +
  72 +func (qrmsg *QrcodeMessage) ParseToken(str string) error {
  73 + tokenClaims, err := jwt.ParseWithClaims(
  74 + str,
  75 + qrmsg,
  76 + func(token *jwt.Token) (interface{}, error) {
  77 + return []byte(loginTokenSecret), nil
  78 + })
  79 + if err != nil {
  80 + return err
  81 + }
  82 + if claim, ok := tokenClaims.Claims.(*QrcodeMessage); ok && tokenClaims.Valid {
  83 + *qrmsg = *claim
  84 + }
  85 + return nil
  86 +}
1 package cache 1 package cache
2 2
  3 +import (
  4 + "encoding/json"
  5 + "time"
  6 +
  7 + "gitlab.fjmaimaimai.com/allied-creation/allied-creation-gateway/pkg/domain"
  8 +)
  9 +
3 //二维码信息缓存 10 //二维码信息缓存
4 type LoginQrcodeCache struct { 11 type LoginQrcodeCache struct {
5 } 12 }
  13 +
  14 +func (lq LoginQrcodeCache) keyString(str string) string {
  15 + str1 := KEY_PREFIX + "login:qrcode:" + str
  16 + return str1
  17 +}
  18 +
  19 +func (lq LoginQrcodeCache) Save(qrcode domain.QrcodeMessage) error {
  20 + nowTime := time.Now().Unix()
  21 + exp := qrcode.ExpiresAt - nowTime
  22 + if exp <= 0 {
  23 + exp = 60 * 60 * 2
  24 + }
  25 + key := lq.keyString(qrcode.Id)
  26 + bt, _ := json.Marshal(qrcode)
  27 + result := clientRedis.Set(key, string(bt), time.Duration(exp))
  28 + return result.Err()
  29 +}
  30 +
  31 +func (lq LoginQrcodeCache) Remove(id string) error {
  32 + keyStr := lq.keyString(id)
  33 + result := clientRedis.Del(keyStr)
  34 + return result.Err()
  35 +}
  36 +
  37 +func (lq LoginQrcodeCache) Get(id string) (*domain.QrcodeMessage, error) {
  38 + keyStr := lq.keyString(id)
  39 + result := clientRedis.Get(keyStr)
  40 + re, _ := result.Result()
  41 + var data domain.QrcodeMessage
  42 + err := json.Unmarshal([]byte(re), &data)
  43 + if err != nil {
  44 + return nil, err
  45 + }
  46 + return &data, err
  47 +}
@@ -3,6 +3,11 @@ package allied_creation_cooperation @@ -3,6 +3,11 @@ package allied_creation_cooperation
3 //确定预算分红激励 3 //确定预算分红激励
4 type ( 4 type (
5 ReqDividendsEstimateIncentive struct { 5 ReqDividendsEstimateIncentive struct {
  6 + // companyId
  7 + // orgId
  8 + // userId
  9 + CooperationContractNumber string //合约编号
  10 + OrderOrReturnedOrderNum string //分红订单号/退货单号
6 } 11 }
7 12
8 DataDividendsEstimateIncentive struct { 13 DataDividendsEstimateIncentive struct {