@@ -17,10 +17,13 @@ limitations under the License.
1717package login
1818
1919import (
20+ "errors"
2021 "fmt"
2122 "time"
2223
24+ "github.com/go-sql-driver/mysql"
2325 "github.com/golang-jwt/jwt"
26+ "github.com/google/uuid"
2427 "github.com/mojocn/base64Captcha"
2528 "github.com/patrickmn/go-cache"
2629 "go.uber.org/zap"
@@ -29,12 +32,14 @@ import (
2932 configbase "github.com/koderover/zadig/v2/pkg/config"
3033 "github.com/koderover/zadig/v2/pkg/microservice/user/config"
3134 "github.com/koderover/zadig/v2/pkg/microservice/user/core/repository"
35+ "github.com/koderover/zadig/v2/pkg/microservice/user/core/repository/models"
3236 "github.com/koderover/zadig/v2/pkg/microservice/user/core/repository/orm"
3337 "github.com/koderover/zadig/v2/pkg/microservice/user/core/service/common"
3438 "github.com/koderover/zadig/v2/pkg/setting"
3539 "github.com/koderover/zadig/v2/pkg/shared/client/aslan"
3640 "github.com/koderover/zadig/v2/pkg/shared/client/plutusvendor"
3741 zadigCache "github.com/koderover/zadig/v2/pkg/tool/cache"
42+ "github.com/koderover/zadig/v2/pkg/tool/log"
3843)
3944
4045type LoginArgs struct {
@@ -271,3 +276,133 @@ func GetCaptcha(logger *zap.SugaredLogger) (string, string, error) {
271276 }
272277 return id , b64s , nil
273278}
279+
280+ type SsoTokenClaims struct {
281+ UserID string `json:"userId"`
282+ Account string `json:"account"`
283+ jwt.StandardClaims
284+ }
285+
286+ func SsoTokenCallback (tokenString string , logger * zap.SugaredLogger ) (string , error ) {
287+ parsedToken , err := jwt .ParseWithClaims (tokenString , & SsoTokenClaims {}, func (token * jwt.Token ) (interface {}, error ) {
288+ return []byte (configbase .SsoTokenSecret ()), nil
289+ })
290+ if err != nil {
291+ return "" , err
292+ }
293+
294+ claims , ok := parsedToken .Claims .(* SsoTokenClaims )
295+ if ! ok || ! parsedToken .Valid {
296+ return "" , fmt .Errorf ("invalid token" )
297+ }
298+
299+ log .Infof ("[SsoTokenCallback]: userId: %s, account: %s" , claims .UserID , claims .Account )
300+
301+ var userLogin * models.UserLogin
302+ identityType := config .SsoTokenIdentityType
303+ user , err := orm .GetUser (claims .UserID , identityType , repository .DB )
304+ if err != nil {
305+ err = fmt .Errorf ("SsoTokenLogin get user account:%s error, error msg:%s" , claims .UserID , err .Error ())
306+ log .Errorf (err .Error ())
307+ return "" , err
308+ }
309+ if user == nil {
310+ uid , _ := uuid .NewUUID ()
311+ user := & models.User {
312+ Name : claims .Account ,
313+ Email : fmt .Sprintf ("%s-%s@poc.example" , claims .UserID , claims .Account ),
314+ IdentityType : identityType ,
315+ Account : claims .UserID ,
316+ UID : uid .String (),
317+ }
318+
319+ tx := repository .DB .Begin ()
320+ defer func () {
321+ if r := recover (); r != nil {
322+ tx .Rollback ()
323+ }
324+ }()
325+ err = orm .CreateUser (user , tx )
326+ if err != nil {
327+ tx .Rollback ()
328+ logger .Errorf ("[SsoTokenCallback] CreateUser :%v error, error msg:%s" , user , err .Error ())
329+ var mysqlErr * mysql.MySQLError
330+ if errors .As (err , & mysqlErr ) && mysqlErr .Number == 1062 {
331+ return "" , fmt .Errorf ("存在相同用户名" )
332+ }
333+ return "" , fmt .Errorf ("创建用户失败, error: %s" , err .Error ())
334+ }
335+ userLogin := & models.UserLogin {
336+ UID : user .UID ,
337+ LastLoginTime : time .Now ().Unix (),
338+ LoginId : user .Account ,
339+ LoginType : int (config .AccountLoginType ),
340+ }
341+ err = orm .CreateUserLogin (userLogin , tx )
342+ if err != nil {
343+ tx .Rollback ()
344+ err = fmt .Errorf ("[SsoTokenCallback] CreateUserLogin:%v error, error msg:%s" , user , err .Error ())
345+ log .Errorf (err .Error ())
346+ return "" , err
347+ }
348+ if tx .Commit ().Error != nil {
349+ return "" , fmt .Errorf ("创建用户登录信息失败, error: %s" , tx .Commit ().Error )
350+ }
351+ } else {
352+ userLogin , err = orm .GetUserLogin (user .UID , claims .UserID , config .AccountLoginType , repository .DB )
353+ if err != nil {
354+ err = fmt .Errorf ("SsoTokenLogin get user:%s user login not exist, error msg:%s" , claims .UserID , err .Error ())
355+ log .Errorf (err .Error ())
356+ return "" , err
357+ }
358+ }
359+
360+ if userLogin != nil {
361+ err = CheckSignature (userLogin .LastLoginTime , logger )
362+ if err != nil {
363+ return "" , err
364+ }
365+ }
366+
367+ userLogin .LastLoginTime = time .Now ().Unix ()
368+ err = orm .UpdateUserLogin (userLogin .UID , userLogin , repository .DB )
369+ if err != nil {
370+ err = fmt .Errorf ("[SsoTokenCallback] user:%s update user login info error, error msg:%s" , claims .UserID , err .Error ())
371+ log .Errorf (err .Error ())
372+ return "" , err
373+ }
374+
375+ systemSettings , err := aslan .New (configbase .AslanServiceAddress ()).GetSystemSecurityAndPrivacySettings ()
376+ if err != nil {
377+ err = fmt .Errorf ("failed to get system security settings, error: %s" , err )
378+ log .Errorf (err .Error ())
379+ return "" , err
380+ }
381+
382+ token , err := CreateToken (& Claims {
383+ Name : user .Name ,
384+ UID : user .UID ,
385+ Email : user .Email ,
386+ PreferredUsername : user .Account ,
387+ StandardClaims : jwt.StandardClaims {
388+ Audience : setting .ProductName ,
389+ ExpiresAt : time .Now ().Add (time .Duration (systemSettings .TokenExpirationTime ) * time .Hour ).Unix (),
390+ },
391+ FederatedClaims : FederatedClaims {
392+ ConnectorId : user .IdentityType ,
393+ UserId : user .Account ,
394+ },
395+ })
396+ if err != nil {
397+ err = fmt .Errorf ("[SsoTokenCallback] user:%s create token error, error msg:%s" , claims .UserID , err .Error ())
398+ log .Errorf (err .Error ())
399+ return "" , err
400+ }
401+
402+ err = zadigCache .NewRedisCache (config .RedisUserTokenDB ()).Write (user .UID , token , time .Duration (systemSettings .TokenExpirationTime )* time .Hour )
403+ if err != nil {
404+ logger .Errorf ("failed to write token into cache, error: %s\n warn: this will cause login failure" , err )
405+ }
406+
407+ return token , nil
408+ }
0 commit comments