github.com/infraboard/keyauth@v0.8.1/apps/session/impl/user.go (about)

     1  package impl
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/infraboard/mcube/exception"
     9  	"github.com/infraboard/mcube/types/ftime"
    10  	"go.mongodb.org/mongo-driver/mongo"
    11  
    12  	"github.com/infraboard/keyauth/apps/session"
    13  	"github.com/infraboard/keyauth/apps/token"
    14  )
    15  
    16  func (s *service) Login(ctx context.Context, tk *token.Token) (*session.Session, error) {
    17  	if tk.IsRefresh() {
    18  		sess, err := s.DescribeSession(ctx, session.NewDescribeSessionRequestWithID(tk.SessionId))
    19  		if err != nil {
    20  			return nil, err
    21  		}
    22  
    23  		sess.AccessToken = tk.AccessToken
    24  		if err := s.updateSession(sess); err != nil {
    25  			return nil, err
    26  		}
    27  		return sess, nil
    28  	}
    29  
    30  	// 关闭之前的session
    31  	s.closeOldSession(ctx, tk)
    32  
    33  	sess, err := session.NewSession(tk)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  
    38  	// 填充session IP信息
    39  	sess.IpInfo, err = s.parseRemoteIPInfo(tk.GetRemoteIp())
    40  	if err != nil {
    41  		s.log.Errorf("parse remote ip error, %s", err)
    42  	}
    43  
    44  	if err := s.saveSession(sess); err != nil {
    45  		return nil, err
    46  	}
    47  	s.log.Infof("user(%s) session: %s login at: %d", sess.Account, sess.Id, sess.LoginAt)
    48  	return sess, nil
    49  }
    50  
    51  func (s *service) parseRemoteIPInfo(ip string) (*session.IPInfo, error) {
    52  	if ip == "" {
    53  		return nil, nil
    54  	}
    55  
    56  	info, err := s.ip.LookupIP(ip)
    57  	if err != nil {
    58  		return nil, fmt.Errorf("parse ipinfo error, %s", err)
    59  	}
    60  
    61  	return &session.IPInfo{
    62  		CityId:   info.CityID,
    63  		Country:  info.Country,
    64  		Region:   info.Region,
    65  		Province: info.Province,
    66  		City:     info.City,
    67  		Isp:      info.ISP,
    68  	}, nil
    69  }
    70  
    71  // 判断用户之前的会话是否正常退出
    72  // 如果access token已经过期, 则已access token过期时间为登出数据 结束该会话
    73  // 如果该会话的刷新token已经过期, 则已刷新结束时间为登出时间 结束该会话
    74  // 如果token正常, 则已当前时间为登出时间 结束该会话
    75  // 结束会话后, 禁用该token
    76  func (s *service) closeOldSession(ctx context.Context, tk *token.Token) {
    77  	descReq := session.NewDescribeSessionRequestWithToken(tk)
    78  	sess, err := s.DescribeSession(ctx, descReq)
    79  	if err != nil {
    80  		s.log.Errorf("query session error, %s", err)
    81  		return
    82  	}
    83  
    84  	blockReq := token.NewBlockTokenRequest(sess.AccessToken, token.BlockType_OTHER_CLIENT_LOGGED_IN, "session closed by other login")
    85  	preTK, err := s.token.BlockToken(ctx, blockReq)
    86  	if err != nil {
    87  		s.log.Errorf("block previous token error, %s", err)
    88  		return
    89  	}
    90  	sess.LogoutAt = ftime.Time(time.Unix(preTK.EndAt()/1000, 0)).Timestamp()
    91  	sess.NamespaceId = tk.NamespaceId
    92  
    93  	if err := s.updateSession(sess); err != nil {
    94  		s.log.Errorf("block session error, %s", err)
    95  	}
    96  	s.log.Infof("user(%s) session: %s logout at: %d", sess.Account, sess.Id, sess.LogoutAt)
    97  }
    98  
    99  func (s *service) Logout(ctx context.Context, req *session.LogoutRequest) (*session.Session, error) {
   100  	descReq := session.NewDescribeSessionRequestWithID(req.SessionId)
   101  	sess, err := s.DescribeSession(ctx, descReq)
   102  	if err != nil {
   103  		return nil, fmt.Errorf("query session error, %s", err)
   104  	}
   105  
   106  	sess.LogoutAt = ftime.Now().Timestamp()
   107  	if err := s.updateSession(sess); err != nil {
   108  		s.log.Errorf("update session error, %s", err)
   109  	}
   110  	s.log.Infof("user(%s) session: %s logout at: %s", sess.Account, sess.Id, sess.LogoutAt)
   111  	return sess, nil
   112  }
   113  
   114  func (s *service) DescribeSession(ctx context.Context, req *session.DescribeSessionRequest) (*session.Session, error) {
   115  	r, err := newDescribeSession(req)
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  
   120  	ins := session.NewDefaultSession()
   121  	if err := s.col.FindOne(context.TODO(), r.FindFilter(), r.FindOptions()).Decode(ins); err != nil {
   122  		if err == mongo.ErrNoDocuments {
   123  			return nil, exception.NewNotFound("session %s not found", req)
   124  		}
   125  
   126  		return nil, exception.NewInternalServerError("find session %s error, %s", req.SessionId, err)
   127  	}
   128  	return ins, nil
   129  }
   130  
   131  func (s *service) QuerySession(ctx context.Context, req *session.QuerySessionRequest) (*session.Set, error) {
   132  	r, err := newQueryLoginLogRequest(req)
   133  	if err != nil {
   134  		return nil, exception.NewBadRequest("validate query session request error, %s", err)
   135  	}
   136  
   137  	resp, err := s.col.Find(context.TODO(), r.FindFilter(), r.FindOptions())
   138  
   139  	if err != nil {
   140  		return nil, exception.NewInternalServerError("find session error, %s", err)
   141  	}
   142  
   143  	set := session.NewSessionSet()
   144  	// 循环
   145  	for resp.Next(context.TODO()) {
   146  		ins := session.NewDefaultSession()
   147  		if err := resp.Decode(ins); err != nil {
   148  			return nil, exception.NewInternalServerError("decode session error, error is %s", err)
   149  		}
   150  
   151  		set.Add(ins)
   152  	}
   153  
   154  	// count
   155  	count, err := s.col.CountDocuments(context.TODO(), r.FindFilter())
   156  	if err != nil {
   157  		return nil, exception.NewInternalServerError("get session count error, error is %s", err)
   158  	}
   159  	set.Total = count
   160  	return set, nil
   161  }