Gin集成OAuth2
Gin集成OAuth2
简介
OAuth 2.0是一种用于授权的开放标准,允许用户授权第三方应用程序访问他们存储在另一个服务提供商上的资源,而无需将他们的凭据(例如用户名和密码)提供给第三方应用程序。OAuth 2.0提供了一种安全的方法,可以授权对资源进行有限的访问,同时保护用户的私密信息。
在OAuth 2.0授权过程中,有三个角色:资源所有者(即用户)、客户端应用程序(即第三方应用程序)和授权服务器(即服务提供商)。以下是OAuth 2.0授权的基本流程:
授权采用的是OAuth2.0授权模式,而OAuth2.0是用于REST/APIs的代理授权框架(delegated authorization framework),它基于令牌Token的授权,在无需暴露用户密码的情况下,使应用能获取对用户数据的有限访问权限。这种模式会为开发者的应用颁发一个有时效性的令牌 token,使得第三方应用能够通过该令牌获取相关的资源。平常我们常见的第三方登录就是使用OAuth 2.0 协议的。同样地,当一个开发者要通过API获取某些广告账户的数据时,也需要得到广告账户的授权。
- 客户端应用程序向资源所有者请求授权。
- 资源所有者同意授权,向授权服务器发出授权请求。
- 授权服务器验证资源所有者的身份,并向其提供一个授权码。
- 客户端应用程序使用授权码向授权服务器请求访问令牌。
- 授权服务器验证授权码并向客户端应用程序提供访问令牌。
- 客户端应用程序使用访问令牌向资源服务器请求访问资源。
- 资源服务器验证访问令牌,并向客户端应用程序提供资源。
使用方式
目录结构
├── config
│ ├── oauth.yaml
│ └── redis.yaml
├── demo
│ └── demo.go
├── go.mod
├── go.sum
├── main.go
├── model
│ ├── base.go
│ └── credentials.go
├── oauth2
│ └── oauth2.go
└── server
└── server.go
编码流程
- 在model下定义返回的资源信息
package model
type Credentials struct {
Code int `json:"code"`
Message string `json:"message"`
ClientId string `json:"clientId"`
ClientSecret string `json:"clientSecret"`
}
- 在oauth2中定义授权
var (
gServer *server.Server
gClient *store.ClientStore
gManage *manage.Manager
domain = "http://localhost:9094"
)
// 设置token返回格式
func SetTokenFormatResponse(ot oauth2.TokenInfo) map[string]interface{} {
return map[string]interface{}{
"code": 200,
"msg": "success",
}
}
// oauth init
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(SetTokenFormatResponse)
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())
})
}
// token 请求信息
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: domain,
})
if err != nil {
c.JSON(500, &model.Base{
Code: 1000,
Message: err.Error(),
})
c.Abort()
}
c.JSON(200, &model.Credentials{
ClientId: clientId,
ClientSecret: clientSecret,
Message: "success",
Code: 100,
})
}
// 认证
func AuthValidate(c *gin.Context) gin.HandlerFunc {
return func(c *gin.Context) {
_, err := gServer.ValidationBearerToken(c.Request)
if err != nil {
c.JSON(401, &model.Base{
Code: 1001,
Message: err.Error(),
})
c.Abort()
return
} else {
c.Next()
}
}
}
- demo模块定义验证消息
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")
}
- main定义HTTP接口
package main
import (
"gin-oauth2/demo"
"gin-oauth2/oauth2"
"github.com/gin-gonic/gin"
)
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")
}