Golang中间件使用问题求助

Golang中间件使用问题求助 大家好,我在理解中间件的工作原理时遇到了困难。

我正在尝试使用这个SAML认证包(https://github.com/crewjam/saml)来实现一个与基于SAML的单点登录配合的Web应用“服务提供者”。这个中间件工作得很好,但我需要在代码中对其进行一些修改,以覆盖其工作方式。

我需要做的是,在我的代码中创建一个处理程序来替换samlsp/middleware.go中的这个函数:

func (m *Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == m.ServiceProvider.MetadataURL.Path {
		m.ServeMetadata(w, r)
		return
	}

	if r.URL.Path == m.ServiceProvider.AcsURL.Path {
		m.ServeACS(w, r)
		return
	}

	http.NotFoundHandler().ServeHTTP(w, r)
}

我想把它替换成……

func (m *Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/metadata" {
		m.ServeMetadata(w, r)
		return
	}

	if r.URL.Path == "/acs" {
		m.ServeACS(w, r)
		return
	}

	http.NotFoundHandler().ServeHTTP(w, r)
}

到这里我就有点困惑了,我不明白为什么我不能从我自己的代码中调用ServeACS和ServeMetadata函数,比如使用类似samlsp.ServeACS的方式。

我想我可能对中间件和接口之间的关系有点混淆,这两个概念相对于我相当基础的编程经验来说都比较高级。我希望有人能好心提供一个示例,说明如何在我自己的代码中覆盖这个功能。

谢谢


更多关于Golang中间件使用问题求助的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

或许你可以尝试创建自己的中间件结构体,并将其嵌入到SAML中间件结构体中。这样,你的自定义中间件就能访问(“继承”)SAML中间件的方法和字段。然后,你可以用自己的实现来重写SAML中间件的ServeHTTP方法。

type MyMiddleware struct {
	*saml.Middleware
}
func (m *MyMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/metadata" {
		m.ServeMetadata(w, r)
		return
	}

	if r.URL.Path == "/acs" {
		m.ServeACS(w, r)
		return
	}

	http.NotFoundHandler().ServeHTTP(w, r)
}
samlSP, _ := samlsp.New(samlsp.Options{
		// 构建中间件所需的任何选项
	})

m := &MyMiddleware{samlSP}
http.Handle("/saml/", m)

更多关于Golang中间件使用问题求助的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


再次感谢,我之前尝试过类似的方法,但遇到了错误……

m.ServeMetadata 未定义(类型 *MyMiddleware 没有字段或方法 ServeMetadata)编译器[MissingFieldOrMethod]。

结果发现我犯了一个愚蠢的错误,我使用的是该库的 4.5 发布版本,而其中的方法尚未从 serveMetadataserveACS 更改为 ServeMetadataServeACS。我原本以为是我理解错了,但你提供的这个例子表明,我已经尝试过一个本应奏效的类似解决方案,但它没有成功。这促使我去尝试找出它不工作的原因,然后我才意识到方法名称的更改尚未实现!

现在我为这样一个愚蠢的疏忽感到有点尴尬,但非常感谢你为帮助我排查问题所做的所有努力。能有其他人提供一些见解非常有帮助,独自进行项目时,遇到问题无人可问会非常困难。非常感谢你的帮助,非常感谢你抽出时间。

在此期间,我创建了自己的小型中间件,它接收 http.Request,从路径中移除 /saml,然后返回修改后的请求的 ServeHTTP。等库更新后我会再重新审视它。

我认为你实际上并不需要替换该函数。 ServiceProvider.MetadataURL 和 ServiceProvider.AcsURL 都是中间件结构体的导出成员,因此你可以修改/设置它们来实现你想要的效果。

	// 生成你的中间件
	samlSP, _ := samlsp.New(samlsp.Options{
		// 构建中间件所需的任何选项
	})

	// ServiceProvider.MetadataURL 和 ServiceProvider.AcsURL 都是
	// net/url 包中的 url.URL 类型。
	// 我们需要使用该类型来表示 /metadata 和 /acs
	metadataURL, _ := url.Parse("/metadata")
	acsURL, _ := url.Parse("/acs")


	samlSP.ServiceProvider.MetadataURL = metadataURL
	samlSP.ServiceProvider.AcsURL = acsURL

	// 使用中间件
	http.Handle("/saml/", samlSP)	

编辑:是的。根据文档,你可以简单地更改一些成员来修改行为:samlsp package - github.com/crewjam/saml/samlsp - Go Packages

你可以通过替换和/或更改返回的 Middleware 中的 Session、RequestTracker 和 ServiceProvider 来更详细地自定义中间件的行为。

你可以通过嵌入原始中间件并重写ServeHTTP方法来实现自定义路由。以下是具体实现示例:

package main

import (
    "net/http"
    "github.com/crewjam/saml/samlsp"
)

type CustomMiddleware struct {
    *samlsp.Middleware
}

func (m *CustomMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path == "/metadata" {
        m.ServeMetadata(w, r)
        return
    }

    if r.URL.Path == "/acs" {
        m.ServeACS(w, r)
        return
    }

    http.NotFoundHandler().ServeHTTP(w, r)
}

// 使用示例
func main() {
    // 创建原始中间件
    sp, _ := samlsp.New(samlsp.Options{
        URL:               "https://example.com",
        Key:               "private-key",
        Certificate:       "certificate",
        IDPMetadata:       "idp-metadata",
    })
    
    // 包装为自定义中间件
    customMiddleware := &CustomMiddleware{Middleware: sp}
    
    // 使用自定义中间件
    http.Handle("/", customMiddleware)
    http.ListenAndServe(":8080", nil)
}

如果你需要直接调用ServeACS和ServeMetadata,可以通过中间件实例访问:

// 直接调用示例
func handleCustomACS(w http.ResponseWriter, r *http.Request, m *samlsp.Middleware) {
    // 直接调用ServeACS
    m.ServeACS(w, r)
}

func handleCustomMetadata(w http.ResponseWriter, r *http.Request, m *samlsp.Middleware) {
    // 直接调用ServeMetadata
    m.ServeMetadata(w, r)
}

这样你就可以完全控制路由逻辑,同时复用原始中间件的认证功能。

回到顶部