golang轻松管理OAuth2权限范围的插件库scope的使用
Golang轻松管理OAuth2权限范围的插件库scope的使用
Scope是一个用于在Go中轻松管理OAuth2权限范围的库。
使用通配符策略进行范围匹配
import "github.com/SonicRoshan/scope"
scopeA := "read:user:*"
scopeB := "read:user:username"
doesMatch := scope.MatchScopes(scopeA, scopeB)
这个匹配策略的工作方式如下:
users.*
匹配users.read
users.*
匹配users.read.foo
users.read
匹配users.read
users
不匹配users.read
users.read.*
不匹配users.read
users.*.*
不匹配users.read
users.*.*
匹配users.read.own
users.*.*
匹配users.read.own.other
users.read.*
匹配users.read.own
users.read.*
匹配users.read.own.other
users.write.*
不匹配users.read.own
users.*.bar
匹配users.baz.bar
users.*.bar
不匹配users.baz.baz.bar
为读取请求过滤结构体
当客户端请求某些数据时,此函数将消除客户端没有读取范围的结构体中的任何数据。
type user struct {
username string `readScope:"user:read:username"`
email string `readScope:"user:read:email"`
}
func main() {
output := user{username : "Test", email : "Test@Test.com"}
scopesHeldByClient := []string{"user:read:username"}
scope.FilterRead(output, scopesHeldByClient)
// 现在output.email将为nil,因为客户端没有读取email字段所需的scope
output := user{username : "Test", email : "Test@Test.com"}
scopesHeldByClient := []string{"user:read:*"}
scope.FilterRead(&output, scopesHeldByClient)
// 现在output中的任何字段都不会为nil,因为客户端有读取用户结构体中所有内容的scope
}
完整示例Demo
下面是一个完整的示例,展示如何使用scope库来管理OAuth2权限范围:
package main
import (
"fmt"
"github.com/SonicRoshan/scope"
)
type UserProfile struct {
Username string `readScope:"profile:read:username"`
Email string `readScope:"profile:read:email"`
Phone string `readScope:"profile:read:phone"`
Address string `readScope:"profile:read:address"`
}
func main() {
// 示例1: 范围匹配
requiredScope := "profile:read:*"
userScope := "profile:read:email"
if scope.MatchScopes(requiredScope, userScope) {
fmt.Println("Scope匹配成功")
} else {
fmt.Println("Scope不匹配")
}
// 示例2: 结构体字段过滤
profile := UserProfile{
Username: "john_doe",
Email: "john@example.com",
Phone: "1234567890",
Address: "123 Main St",
}
// 客户端只有读取username和email的权限
clientScopes := []string{"profile:read:username", "profile:read:email"}
fmt.Println("过滤前的用户资料:", profile)
scope.FilterRead(&profile, clientScopes)
fmt.Println("过滤后的用户资料:", profile) // Phone和Address字段将被置为零值
}
这个示例展示了:
- 如何使用
MatchScopes
函数检查两个范围是否匹配 - 如何使用
FilterRead
函数根据客户端的权限范围过滤结构体字段
对于没有相应读取权限的字段,它们将被设置为该类型的零值(字符串为空字符串,数字为0等)。
更多关于golang轻松管理OAuth2权限范围的插件库scope的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang轻松管理OAuth2权限范围的插件库scope的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang OAuth2 权限范围管理 - scope 库使用指南
在 Go 语言中管理 OAuth2 的权限范围(scope)可以使用 github.com/ory/fosite
库中的 scope 工具,这是一个功能强大且灵活的解决方案。下面我将详细介绍如何使用它来管理 OAuth2 的权限范围。
安装 scope 库
首先安装必要的依赖:
go get github.com/ory/fosite
go get github.com/ory/fosite/token/jwt
基本使用示例
1. 定义权限范围
package main
import (
"fmt"
"github.com/ory/fosite"
"github.com/ory/fosite/token/jwt"
)
func main() {
// 创建策略
strategy := &jwt.RS256JWTStrategy{
PrivateKey: privateKey, // 需要替换为实际的私钥
}
// 创建范围管理器
scopeManager := fosite.NewScopeStrategy()
// 定义可用的权限范围
availableScopes := fosite.Arguments{
"read",
"write",
"delete",
"admin",
}
// 客户端请求的权限范围
requestedScopes := fosite.Arguments{
"read",
"write",
}
// 验证请求的范围是否在可用范围内
if err := scopeManager(availableScopes, requestedScopes); err != nil {
fmt.Printf("无效的权限范围: %v\n", err)
return
}
fmt.Println("权限范围验证通过")
}
2. 更完整的 OAuth2 服务器实现
package main
import (
"context"
"fmt"
"net/http"
"github.com/ory/fosite"
"github.com/ory/fosite/compose"
"github.com/ory/fosite/storage/memory"
)
func main() {
// 配置 OAuth2 服务器
config := &compose.Config{
AccessTokenLifespan: 3600, // 1小时
}
// 创建存储
store := memory.NewMemoryStore()
// 设置客户端
store.Clients["my-client"] = &fosite.DefaultClient{
ID: "my-client",
Secret: []byte("my-secret"),
GrantTypes: []string{"authorization_code", "refresh_token"},
ResponseTypes: []string{"code"},
RedirectURIs: []string{"http://localhost:3846/callback"},
Scopes: []string{"read", "write", "delete"}, // 客户端允许的范围
}
// 创建 OAuth2 提供者
provider := compose.NewOAuth2Provider(config, store, nil)
// HTTP 处理函数
http.HandleFunc("/authorize", func(w http.ResponseWriter, r *http.Request) {
// 创建授权请求
ar, err := provider.NewAuthorizeRequest(context.Background(), r)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// 检查请求的范围是否有效
requestedScopes := ar.GetRequestedScopes()
allowedScopes := fosite.Arguments{"read", "write"} // 实际允许的范围
// 验证范围
for _, scope := range requestedScopes {
if !allowedScopes.Has(scope) {
http.Error(w, fmt.Sprintf("无效的范围: %s", scope), http.StatusBadRequest)
return
}
}
// 这里通常会显示授权页面,简化处理直接授权
ar.GrantScope("read")
ar.GrantScope("write")
// 创建响应
response, err := provider.NewAuthorizeResponse(context.Background(), ar, nil)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// 返回授权码
provider.WriteAuthorizeResponse(w, ar, response)
})
// 启动服务器
fmt.Println("OAuth2 服务器运行在 :3846")
http.ListenAndServe(":3846", nil)
}
高级用法
1. 自定义范围验证策略
func customScopeStrategy(availableScopes fosite.Arguments, requestedScopes fosite.Arguments) error {
// 实现自定义的范围验证逻辑
for _, scope := range requestedScopes {
if !availableScopes.Has(scope) {
return fosite.ErrInvalidScope.WithHintf("范围 %s 不可用", scope)
}
// 可以添加更复杂的逻辑,如:
if scope == "admin" && !isAdminUser() {
return fosite.ErrInvalidScope.WithHint("需要管理员权限")
}
}
return nil
}
// 在配置中使用自定义策略
config := &compose.Config{
ScopeStrategy: customScopeStrategy,
}
2. 分层范围管理
// 定义分层范围
var scopeHierarchy = map[string][]string{
"admin": {"read", "write", "delete"},
"write": {"read"},
"delete": {"read"},
}
func hierarchicalScopeStrategy(availableScopes fosite.Arguments, requestedScopes fosite.Arguments) error {
for _, scope := range requestedScopes {
if !availableScopes.Has(scope) {
return fosite.ErrInvalidScope.WithHintf("范围 %s 不可用", scope)
}
// 检查依赖范围
if deps, ok := scopeHierarchy[scope]; ok {
for _, dep := range deps {
if !requestedScopes.Has(dep) {
return fosite.ErrInvalidScope.WithHintf("范围 %s 需要 %s 权限", scope, dep)
}
}
}
}
return nil
}
最佳实践
- 最小权限原则:只授予必要的权限范围
- 范围分组:将相关权限组织在一起,如 “user.profile” 和 “user.email”
- 文档清晰:为每个范围提供清晰的文档说明
- 范围过期:考虑为敏感范围设置更短的有效期
- 用户同意:在授权时向用户明确说明每个范围的含义
通过合理使用 scope 管理,可以构建更安全、更灵活的 OAuth2 授权系统。