栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Go语言

【oauth2.0】golang简单实现oauth2.0授权逻辑

Go语言 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【oauth2.0】golang简单实现oauth2.0授权逻辑

oauth2.0鉴权
  • 一、OAuth2
  • 二、授权流程(grant_type)
      • 1、授权码(authorization_code)
      • 2、隐藏式(implicit)
      • 3、密码式(password)
      • 4、客户端凭证(client_credentials)
  • 三、基于oauth2的简单授权流程
      • 1、模拟第三方服务
      • 2、模拟授权验证

参考文档:https://github.com/go-oauth2/oauth2
参考博客:https://www.ruanyifeng.com/blog/2019/04/oauth-grant-types.html

一、OAuth2

拉起三方,获取用户信息,验证,授权,获取用户信息,颁发token

二、授权流程(grant_type) 1、授权码(authorization_code)
  • 用户登陆第三方应用授权, 先拿code(第三方授权码)
  • 用code换token
2、隐藏式(implicit)
  • 用户登陆授权,不拿code,直接获取token
3、密码式(password)
  • 用户提供给客户端 用户名和密码
  • 验证客户端,验证通过,发放token
4、客户端凭证(client_credentials)
  • 验证客户端,直接发放token
三、基于oauth2的简单授权流程 1、模拟第三方服务
package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

// 测试定死了code、token,真实开发应该持久化
var (
	AuthCode        = "CODE_CODE"
	AccessTokenCode = "AccessTokenCode"
)

func main() {
	r := gin.Default()

	// 前端获取 code
	r.POST("/code", Code)
	// 后端通过 code 获取令牌 token
	r.POST("/access_token", AccessToken)
	// 后端通过 token 获取用户信息
	r.POST("/user_info", UserInfo)

	r.Run(":9090")
}

type UserInfoParams struct {
	Token string `json:"token"`
}

func UserInfo(c *gin.Context) {
	params := &UserInfoParams{}
	if err := c.BindJSON(params); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if params.Token != AccessTokenCode {
		c.JSON(http.StatusNoContent, nil)
		return
	}

	c.JSON(200, gin.H{"user_name": "zhangsan", "Age": 20})
}

type TokenParams struct {
	Code string `json:"code"`
}

func AccessToken(c *gin.Context) {
	params := &TokenParams{}
	if err := c.BindJSON(params); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if params.Code != AuthCode {
		c.JSON(200, gin.H{"access_token": ""})
		return
	}

	c.JSON(200, gin.H{"access_token": AccessTokenCode})
}

type CodeParams struct {
	ClientId    string `json:"client_id"`
	Code        string `json:"code"`
	Scope       string `json:"scope"`
	State       string `json:"state"`
	RedirectUri string `json:"redirect_uri"`
}

func Code(c *gin.Context) {
	params := &CodeParams{}
	if err := c.BindJSON(params); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	params.Code = AuthCode

	c.JSON(200, gin.H{"msg": params})
}
2、模拟授权验证
package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"

	"github.com/gin-gonic/gin"
)

var (
	postTokenUrl    = "http://localhost:9090/access_token"
	postUserInfoUrl = "http://localhost:9090/user_info"
)

func main() {
	r := gin.Default()

	// 获取 token
	r.POST("/token", Token)

	r.Run(":9091")
}

type TokenParams struct {
	Code string `json:"code"` // 授权码 是前端拉起第三方页面获取到的code
	// ==== 以下本次测试的用不到 ====
	GrantType   string `json:"grant_type"`   // 授权流程
	RedirectUri string `json:"redirect_uri"` // 重定向uri
}

func Token(c *gin.Context) {
	params := &TokenParams{}
	if err := c.BindJSON(params); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// 1.请求第三方颁发 token
	assToken := &AccToken{}
	Post(assToken, postTokenUrl, "code", params.Code)
	if assToken.AccessToken == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "get assecc_token error"})
		return
	}

	// 2.获取用户信息
	userInfo := &UserInfo{}
	err := Post(userInfo, postUserInfoUrl, "token", assToken.AccessToken)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "user not found"})
		return
	}

	// ------------- 这里做一些判断操作,比如验证用户是否存在,创建/更新/登陆...... ---------------

	c.JSON(200, gin.H{
		"name": userInfo.UserName,
		"age":  userInfo.Age,
	})
}

type UserInfo struct {
	UserName string `json:"user_name"`
	Age      int    `json:"age"`
}
type AccToken struct {
	AccessToken string `json:"access_token"`
}

// 请求工具类
func Post(params interface{}, url string, key string, val string) error {
	client := &http.Client{}
	data := map[string]interface{}{
		key: val,
	}
	reqData, _ := json.Marshal(data)

	req, _ := http.NewRequest("POST", url, bytes.NewReader(reqData))
	resp, _ := client.Do(req)
	respBody, _ := ioutil.ReadAll(resp.Body)
	if len(respBody) == 0 {
		return errors.New("body nil")
	}

	json.Unmarshal(respBody, params)

	return nil
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/944057.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号