Example #1
0
// 跳转后的页面请求处理.
// redirectURL?code=CODE&state=STATE // 授权
// redirectURL?state=STATE           // 不授权
func RedirectURLHandler(w http.ResponseWriter, r *http.Request) {
	if err := r.ParseForm(); err != nil {
		// TODO: 处理 error
		return
	}

	state := r.FormValue("state")

	// TODO: 处理这个 state 参数, 判断是否是有效的

	_ = state // NOTE: 实际开发中不要有这个

	// 假定 state 有效

	if code := r.FormValue("code"); code != "" { // 授权

		client := oauth2.Client{
			OAuth2Config: oauth2Config,
		}
		info, err := client.Exchange(code)
		if err != nil {
			// TODO: ...
			return
		}

		// TODO: 这里把 info 根据 info.OpenId 缓存起来,以后可以直接用
		// 做相应的 session 处理。
		_ = info // NOTE: 示例代码

	} else { // 不授权
		// TODO: 不授权的相应代码
	}
}
Example #2
0
// 在需要用户授权的时候引导用户到授权页面
func SomeHandler(w http.ResponseWriter, r *http.Request) {
	var hasAuth bool // 判断是否授权
	// TODO: 判断 session 里是否有 openid 字段,如果有则表明已经授权,没有则没有授权

	if hasAuth {
		var info *oauth2.OAuth2Info
		// TODO: 根据 openid 字段 找到 info(type == *oauth2.OAuth2Info)

		client := oauth2.Client{
			OAuth2Config: oauth2Config,
			OAuth2Info:   info,
		}

		// 可以根据这个 info 做相应的操作,比如下面的获取用户信息
		userinfo, err := client.UserInfo("zh_CN")
		if err != nil {
			// TODO: ...
			return
		}

		// 处理 userinfo
		_ = userinfo // NOTE: 实际开发中可不是这样的

	} else {
		var state = "state" // NOTE: 实际上是一串不可预测的随机数

		// TODO: state 做相应处理,好识别下次跳转回来的 state 参数

		http.Redirect(w, r, oauth2Config.AuthCodeURL(state), http.StatusFound)
	}
}
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
	}
}