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"