Example #1
0
// 认证成功后创建 token 和 session
func authSuccess(ctx *gin.Context, authType string, user *model.User) {
	sid, err := session.NewSessionId()
	if err != nil {
		glog.Errorln(err)
		ctx.JSON(200, errors.ErrInternalServerError)
		return
	}

	timestamp := time.Now().Unix()
	tk := token.Token{
		SessionId:         sid,
		TokenId:           token.NewTokenId(),
		AuthType:          authType,
		ExpirationAccess:  token.ExpirationAccess(timestamp),
		ExpirationRefresh: token.ExpirationRefresh(timestamp),
	}
	tkEncodedBytes, err := tk.Encode()
	if err != nil {
		glog.Errorln(err)
		ctx.JSON(200, errors.ErrTokenEncodeFailed)
		return
	}

	ss := session.Session{
		TokenSignature: tk.Signatrue,
		UserId:         user.Id,
		PasswordTag:    user.PasswordTag,
	}
	if err = session.Add(sid, &ss); err != nil {
		glog.Errorln(err)
		ctx.JSON(200, errors.ErrInternalServerError)
		return
	}

	resp := struct {
		*errors.Error
		Token string `json:"token"`
	}{
		Error: errors.ErrOK,
		Token: string(tkEncodedBytes),
	}
	ctx.JSON(200, &resp)
	return
}
Example #2
0
// 刷新 token
func RefreshHandler(ctx *gin.Context) {
	tkString := ctx.Request.Header.Get("x-token")
	if tkString == "" {
		ctx.JSON(200, errors.ErrTokenMissing)
		return
	}

	// 解析 token
	tk := &token.Token{}
	if err := tk.Decode([]byte(tkString)); err != nil {
		glog.Errorln(err)
		ctx.JSON(200, errors.ErrTokenDecodeFailed)
		return
	}

	// 如果是 guest 直接返回
	if tk.AuthType == token.AuthTypeGuest {
		resp := struct {
			*errors.Error
			Token string `json:"token"`
		}{
			Error: errors.ErrOK,
			Token: tkString,
		}
		ctx.JSON(200, &resp)
		return
	}

	timestamp := time.Now().Unix()
	if timestamp >= tk.ExpirationRefresh {
		ctx.JSON(200, errors.ErrTokenRefreshExpired)
		return
	}
	if timestamp+1200 < tk.ExpirationAccess { // 过早的刷新也是直接返回
		resp := struct {
			*errors.Error
			Token string `json:"token"`
		}{
			Error: errors.ErrOK,
			Token: tkString,
		}
		ctx.JSON(200, &resp)
		return
	}
	if tk.ExpirationAccess >= tk.ExpirationRefresh { // 提前 1200秒 暴力的结束, 防止客户端循环的刷新
		ctx.JSON(200, errors.ErrTokenRefreshExpired)
		return
	}

	// 现在我们真的需要刷新token啦!!!

	// 获取 Session 并判断与 token 是否匹配
	ss, err := session.Get(tk.SessionId)
	if err != nil {
		glog.Errorln(err)
		if err == errors.ErrNotFound {
			ctx.JSON(200, errors.ErrTokenInvalid)
			return
		}
		ctx.JSON(200, errors.ErrInternalServerError)
		return
	}
	if !security.SecureCompareString(tk.Signatrue, ss.TokenSignature) {
		ctx.JSON(200, errors.ErrTokenInvalid)
		return
	}

	// 获取用户信息并判断与 token, session 是否一致
	user, err := model.Get(ss.UserId)
	if err != nil {
		glog.Errorln(err)
		if err == model.ErrNotFound {
			ctx.JSON(200, errors.ErrTokenInvalid)
			return
		}
		ctx.JSON(200, errors.ErrInternalServerError)
		return
	}
	bindType, err := token.GetBindType(tk.AuthType)
	if err != nil {
		glog.Errorln(err)
		ctx.JSON(200, errors.ErrTokenInvalid)
		return
	}
	if user.BindTypes&bindType == 0 {
		ctx.JSON(200, errors.ErrTokenInvalid)
		return
	}
	if tk.AuthType == token.AuthTypeEmailPassword || tk.AuthType == token.AuthTypePhonePassword {
		if ss.PasswordTag != user.PasswordTag {
			ctx.JSON(200, errors.ErrTokenInvalid)
			return
		}
	}

	tk2 := token.Token{
		SessionId:         tk.SessionId,
		TokenId:           token.NewTokenId(),
		AuthType:          tk.AuthType,
		ExpirationAccess:  token.ExpirationAccess(timestamp),
		ExpirationRefresh: tk.ExpirationRefresh,
	}
	if tk2.ExpirationAccess > tk2.ExpirationRefresh {
		tk2.ExpirationAccess = tk2.ExpirationRefresh
	}
	tk2EncodedBytes, err := tk2.Encode()
	if err != nil {
		glog.Errorln(err)
		ctx.JSON(200, errors.ErrTokenEncodeFailed)
		return
	}

	ss.TokenSignature = tk2.Signatrue
	if err = session.Set(tk2.SessionId, ss); err != nil {
		glog.Errorln(err)
		ctx.JSON(200, errors.ErrInternalServerError)
		return
	}

	resp := struct {
		*errors.Error
		Token string `json:"token"`
	}{
		Error: errors.ErrOK,
		Token: string(tk2EncodedBytes),
	}
	ctx.JSON(200, &resp)
	return
}
Example #3
0
// 微信 oauth2 认证
//  需要提供 code, state 参数.
func AuthHandler(ctx *gin.Context) {
	// MustAuthHandler(ctx)
	queryValues := ctx.Request.URL.Query()
	code := queryValues.Get("code")
	if code == "" {
		ctx.JSON(200, errors.ErrBadRequest)
		return
	}
	state := queryValues.Get("state")
	if state == "" {
		ctx.JSON(200, errors.ErrBadRequest)
		return
	}

	ss := ctx.MustGet("sso_session").(*session.Session)

	// 比较 state 是否一致
	if !security.SecureCompareString(state, ss.OAuth2State) {
		ctx.JSON(200, errors.ErrOAuthStateMismatch)
		return
	}

	oauth2Client := oauth2.Client{
		Config: oauth2Config,
	}
	oauth2Token, err := oauth2Client.Exchange(code)
	if err != nil {
		glog.Errorln(err)
		ctx.JSON(200, errors.ErrInternalServerError)
		return
	}
	if oauth2Token.UnionId == "" {
		glog.Errorln("unionid is empty")
		ctx.JSON(200, errors.ErrInternalServerError)
		return
	}

	timestamp := time.Now().Unix()
	user, err := model.GetByWechat(oauth2Token.UnionId)
	switch err {
	default:
		glog.Errorln(err)
		ctx.JSON(200, errors.ErrInternalServerError)
		return
	case model.ErrNotFound:
		var oauth2UserInfo openOAuth2.UserInfo
		if err = oauth2Client.GetUserInfo(&oauth2UserInfo, ""); err != nil {
			glog.Errorln(err)
			ctx.JSON(200, errors.ErrInternalServerError)
			return
		}

		user, err = model.AddByWechat(oauth2Token.UnionId, oauth2UserInfo.Nickname, timestamp)
		if err != nil {
			glog.Errorln(err)
			ctx.JSON(200, errors.ErrInternalServerError)
			return
		}
		fallthrough
	case nil:
		sid, err := session.NewSessionId()
		if err != nil {
			glog.Errorln(err)
			ctx.JSON(200, errors.ErrInternalServerError)
			return
		}

		tk2 := token.Token{
			SessionId:         sid,
			TokenId:           token.NewTokenId(),
			AuthType:          token.AuthTypeOAuthWechat,
			ExpirationAccess:  token.ExpirationAccess(timestamp),
			ExpirationRefresh: token.ExpirationRefresh(timestamp),
		}
		tk2EncodedBytes, err := tk2.Encode()
		if err != nil {
			glog.Errorln(err)
			ctx.JSON(200, errors.ErrTokenEncodeFailed)
			return
		}

		ss2 := session.Session{
			TokenSignature: tk2.Signatrue,
			UserId:         user.Id,
			PasswordTag:    user.PasswordTag,
		}
		if err = session.Add(sid, &ss2); err != nil {
			glog.Errorln(err)
			ctx.JSON(200, errors.ErrInternalServerError)
			return
		}

		resp := struct {
			*errors.Error
			Token string `json:"token"`
		}{
			Error: errors.ErrOK,
			Token: string(tk2EncodedBytes),
		}
		ctx.JSON(200, &resp)
		return
	}
}