golang轻松管理OAuth2权限范围的插件库scope的使用

Golang轻松管理OAuth2权限范围的插件库scope的使用

Go Report Card GoDoc GoCover

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字段将被置为零值
}

这个示例展示了:

  1. 如何使用MatchScopes函数检查两个范围是否匹配
  2. 如何使用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
}

最佳实践

  1. 最小权限原则:只授予必要的权限范围
  2. 范围分组:将相关权限组织在一起,如 “user.profile” 和 “user.email”
  3. 文档清晰:为每个范围提供清晰的文档说明
  4. 范围过期:考虑为敏感范围设置更短的有效期
  5. 用户同意:在授权时向用户明确说明每个范围的含义

通过合理使用 scope 管理,可以构建更安全、更灵活的 OAuth2 授权系统。

回到顶部