golang gin框架实现oauth2

1.获取依赖包

go get github.com/gin-gonic/gin
go get gopkg.in/oauth2.v3
go get github.com/google/uuid

2.项目结构和源码

​项目地址​

3.主要文件说明

main.go

package main

import (
"github.com/gin-gonic/gin"
"logistics/demo"
"logistics/oauth2"
)


func main() {
g := gin.Default()
auth := g.Group("/auth")
{
auth.GET("/token", oauth2.TokenRequest)
auth.GET("/credentials",oauth2.Credentials)
}
de := g.Group("/demo")
{
de.GET("/message",demo.Message)
}
de1 := g.Group("/demo1")
{
var c *gin.Context
//权限认证中间件
de1.Use(oauth2.AuthValidate(c))
de1.GET("/message",demo.Message1)
}
g.Run(":9096")
}

ginOauth.go

package oauth2

import (
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"gopkg.in/oauth2.v3"
"gopkg.in/oauth2.v3/errors"
"gopkg.in/oauth2.v3/manage"
"gopkg.in/oauth2.v3/models"
"gopkg.in/oauth2.v3/server"
"gopkg.in/oauth2.v3/store"
"log"
"logistics/model"
"time"
)

var (
gServer *server.Server
gClient *store.ClientStore
gManage *manage.Manager
baseResponse *model.Base
credentialsResponse *model.Credentials
)

/**
统一token返回格式
*/
func SetExtensionFields(ti oauth2.TokenInfo) map[string]interface{}{
data := map[string]interface{}{
"code": 1,
"message": "success",
}
return data
}

func init() {
gManage = manage.NewDefaultManager()
gManage.MustTokenStorage(store.NewMemoryTokenStore())
gClient = store.NewClientStore()
gManage.MapClientStorage(gClient)
gServer = server.NewDefaultServer(gManage)
gServer.SetAllowGetAccessRequest(true)
gServer.SetClientInfoHandler(server.ClientFormHandler)
var cfg = &manage.Config{AccessTokenExp: time.Hour * 200, RefreshTokenExp: time.Hour * 24 * 300, IsGenerateRefresh: true}
gManage.SetAuthorizeCodeTokenCfg(cfg)
gManage.SetRefreshTokenCfg(manage.DefaultRefreshTokenCfg)
gManage.SetClientTokenCfg(cfg)
gServer.SetExtensionFieldsHandler(SetExtensionFields)
gServer.SetInternalErrorHandler(func(err error) (re *errors.Response) {
log.Println("Internal Error:", err.Error())
return
})

gServer.SetResponseErrorHandler(func(re *errors.Response) {
log.Println("Response Error:", re.Error.Error())
})
}


func TokenRequest(c *gin.Context){
gServer.HandleTokenRequest(c.Writer, c.Request)
}

func Credentials(c *gin.Context){
clientId := uuid.New().String()[:16]
clientSecret := uuid.New().String()[:16]
err := gClient.Set(clientId, &models.Client{
ID: clientId,
Secret: clientSecret,
Domain: "http://localhost:9094",
})
if err != nil {
baseResponse = &model.Base{}
baseResponse.Code = 1000
baseResponse.Message = err.Error()
c.JSON(500, baseResponse)
c.Abort()
}
credentialsResponse = &model.Credentials{}
credentialsResponse.Code = 1
credentialsResponse.Message = "success"
credentialsResponse.ClientId = clientId
credentialsResponse.ClientSecret = clientSecret
c.JSON(200, credentialsResponse)
}

/**
权限验证中间件
*/
func AuthValidate(c *gin.Context) gin.HandlerFunc{
return func(c *gin.Context) {
_, err := gServer.ValidationBearerToken(c.Request)
if err != nil {
baseResponse = &model.Base{}
baseResponse.Code = 1001
baseResponse.Message = err.Error()
c.JSON(401, baseResponse)
c.Abort()
return
}else{
c.Next()
}

}
}

base.go

package model

type Base struct {
Code int `json:"code"`
Message string `json:"message"`
}

credentials.go

package model

type Credentials struct {
Base
ClientId string `json:"clientId"`
ClientSecret string `json:"clientSecret"`
}

test.go

package demo

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

func Message(c *gin.Context){
c.JSON(200, "I not need auth")
}

func Message1(c *gin.Context){
c.JSON(200, "I need auth")
}

4.说明

代码中的

  clientId := uuid.New().String()[:16]
clientSecret := uuid.New().String()[:16]

可以修改成固定值方便测试

5.请求

首先获取Credentials ​​http://localhost:9096/auth/credentials​​ 返回结果

{
"code": 1,
"message": "success",
"clientId": "a02156b4-1a46-43",
"clientSecret": "98871767-3760-46"
}

然后再获取accessToken ​​http://localhost:9096/auth/token?grant_type=client_credentials&client_id=a02156b4-1a46-431&client_secret=98871767-3760-46&scope=all​​ 返回结果

{
"access_token": "DK0LDFEHPEA19DCBXN8-2W",
"code": 1,
"expires_in": 720000,
"message": "success",
"refresh_token": "YCLVAWSKWGIV___ZNJIGDQ",
"scope": "all",
"token_type": "Bearer"
}

原来是没有code和message,为了统一增加的。

请求接口 ​​http://localhost:9096/demo/message​​ 这个不需要授权可以访问 返回结果

"I not need auth"

请求接口 ​​http://localhost:9096/demo1/message​​ 不加授权返回

{
"code": 1001,
"message": "invalid access token"
}

增加授权返回

"I need auth"