社交网络 VK 的认证与 Martini

huangapple go评论93阅读模式
英文:

social network vk auth with martini

问题

我正在尝试在martini中使用vk auth。但在编译时出现错误:

/goPath/vkAuthTry2.go:38: undefined: YourRedirectFunc

问题是如何定义YourRedirectFunc函数。或者更广泛地说,我需要一个使用vk社交网络身份验证的martini应用的工作示例,或者更广泛地说,任何使用vk身份验证的golang网站的示例。

完整代码:

package main

import (
    "github.com/go-martini/martini"
    "github.com/yanple/vk_api"
    "net/http"
)

var api vk_api.Api

func prepareMartini() *martini.ClassicMartini {
    m := martini.Classic()
    m.Get("/somePage", func(w http.ResponseWriter, r *http.Request) {
        //  And receive token on the special method (redirect uri)
        currentUrl := r.URL.RequestURI() // for example "yoursite.com/get_access_token#access_token=3304fdb7c3b69ace6b055c6cba34e5e2f0229f7ac2ee4ef46dc9f0b241143bac993e6ced9a3fbc111111&expires_in=0&user_id=1"
        accessToken, userId, expiresIn, err := vk_api.ParseResponseUrl(currentUrl)
        if err != nil {
            panic(err)
        }
        api.AccessToken = accessToken
        api.UserId = userId
        api.ExpiresIn = expiresIn
        w.Write([]byte("somePage"))
    })
    return m
}

func main() {
    authUrl, err := api.GetAuthUrl(
        "domain.com/method_get_access_token", // redirect URI
        "token",        // response type
        "4672050",      // client id
        "wall,offline", // permissions https://vk.com/dev/permissions
    )
    if err != nil {
        panic(err)
    }
    YourRedirectFunc(authUrl)
    prepareMartini().Run()
}

更新:
根据@Elwinar的答案,我编辑了我的代码:

package main

import (
    "fmt"
    "github.com/go-martini/martini"
    "github.com/yanple/vk_api"
    "net/http"
)

var api vk_api.Api

func prepareMartini() *martini.ClassicMartini {
    m := martini.Classic()
    // This handler redirect the request to the vkontact system, which
    // will perform the authentification then redirect the request to
    // the URL we gave as the first paraemeter of the GetAuthUrl method
    // (treated by the second handler)
    m.Get("/vk/auth", func(w http.ResponseWriter, r *http.Request) {
        var api vk_api.Api
        authUrl, err := api.GetAuthUrl("http://localhost:3000/vk/token", "token", "4672050", "wall,offline")
        if err != nil {
            panic(err)
        }

        http.Redirect(w, r, authUrl, http.StatusFound)
    })

    // This handler is the one that get the actual authentification
    // information from the vkontact api. You get the access token,
    // userid and expiration date of the authentification session.
    // You can do whatever you want with them, generally storing them
    // in session to be able to get the actual informations later using
    // the access token.
    m.Get("/vk/token", func(w http.ResponseWriter, r *http.Request) {
        accessToken, userId, expiresIn, err := vk_api.ParseResponseUrl(r.URL.String())
        if err != nil {
            panic(err)
        }
        fmt.Println(accessToken)
        fmt.Println(userId)
        fmt.Println(expiresIn)
    })
    return m
}

func main() {
    prepareMartini().Run()
}

现在没有编译错误,但仍然无法登录。
当我打开http://localhost:3000/vk/auth时,我被重定向到页面...

https://oauth.vk.com/authorize?client_id=MY_APP_ID&redirect_uri=localhost%3A3000%2Fvk%2Ftoken&response_type=token&scope=wall%2Coffline

...并得到以下浏览器输出:

{"error":"invalid_request","error_description":"redirect_uri is incorrect, check application domain in the settings page"}

当然,我将4672050替换为我的应用程序ID。这个应用程序是专门为localhost:3000生成的。
也许我需要在某个地方粘贴我的私钥,例如pYFR2Xojlkad87880dLa

更新2:
@qwertmax的答案几乎可以工作。我已经成功通过vk登录,但是我的代码打印出空行,而不是userId和其他用户信息:

accessToken, userId, expiresIn, err := vk_api.ParseResponseUrl(r.URL.String())

fmt.Println(accessToken)
fmt.Println(userId)
fmt.Println(expiresIn)
英文:

I am trying to use vk auth with martini. But have error on compile:

/goPath/vkAuthTry2.go:38: undefined: YourRedirectFunc

The question is how to define YourRedirectFunc function. Or if ask more widely I need working example of martini app with vk social network authentication or if even more widely an example of any golang website using vk authentication.

Full code:

package main

import (
    "github.com/go-martini/martini"
    "github.com/yanple/vk_api"
    "net/http"
)

var api vk_api.Api

func prepareMartini() *martini.ClassicMartini {
    m := martini.Classic()
    m.Get("/somePage", func(w http.ResponseWriter, r *http.Request) {
        //  And receive token on the special method (redirect uri)
        currentUrl := r.URL.RequestURI() // for example "yoursite.com/get_access_token#access_token=3304fdb7c3b69ace6b055c6cba34e5e2f0229f7ac2ee4ef46dc9f0b241143bac993e6ced9a3fbc111111&expires_in=0&user_id=1"
        accessToken, userId, expiresIn, err := vk_api.ParseResponseUrl(currentUrl)
        if err != nil {
            panic(err)
        }
        api.AccessToken = accessToken
        api.UserId = userId
        api.ExpiresIn = expiresIn
        w.Write([]byte("somePage"))
    })
    return m
}

func main() {
    authUrl, err := api.GetAuthUrl(
        "domain.com/method_get_access_token", // redirect URI
        "token",        // response type
        "4672050",      // client id
        "wall,offline", // permissions https://vk.com/dev/permissions
    )
    if err != nil {
        panic(err)
    }
    YourRedirectFunc(authUrl)
    prepareMartini().Run()
}

Update

I edited my code according to @Elwinar's answer:

package main

import (
    "fmt"
    "github.com/go-martini/martini"
    "github.com/yanple/vk_api"
    "net/http"
)

var api vk_api.Api

func prepareMartini() *martini.ClassicMartini {
    m := martini.Classic()
    // This handler redirect the request to the vkontact system, which
    // will perform the authentification then redirect the request to
    // the URL we gave as the first paraemeter of the GetAuthUrl method
    // (treated by the second handler)
    m.Get("/vk/auth", func(w http.ResponseWriter, r *http.Request) {
        var api vk_api.Api
        authUrl, err := api.GetAuthUrl("http://localhost:3000/vk/token", "token", "4672050", "wall,offline")
        if err != nil {
            panic(err)
        }

        http.Redirect(w, r, authUrl, http.StatusFound)
    })

    // This handler is the one that get the actual authentification
    // information from the vkontact api. You get the access token,
    // userid and expiration date of the authentification session.
    // You can do whatever you want with them, generally storing them
    // in session to be able to get the actual informations later using
    // the access token.
    m.Get("/vk/token", func(w http.ResponseWriter, r *http.Request) {
        accessToken, userId, expiresIn, err := vk_api.ParseResponseUrl(r.URL.String())
        if err != nil {
            panic(err)
        }
        fmt.Println(accessToken)
        fmt.Println(userId)
        fmt.Println(expiresIn)
    })
    return m
}

func main() {
    prepareMartini().Run()
}

now no complie errors, but still cannot login.
When I opened http://localhost:3000/vk/auth I was redirected on page...

https://oauth.vk.com/authorize?client_id=MY_APP_ID&redirect_uri=localhost%3A3000%2Fvk%2Ftoken&response_type=token&scope=wall%2Coffline

... and got the following browser output:

{"error":"invalid_request","error_description":"redirect_uri is incorrect, check application domain in the settings page"}

Of course instead of 4672050 I pasted my app id. This app was specially generated for localhost:3000.
Maybe I need to paste somewhere my private key for oauth like pYFR2Xojlkad87880dLa.

Update 2

@qwertmax's answer almost works. I have successfully logged in by vk, but my code prints empty lines instead of userId and another user information:

 accessToken, userId, expiresIn, err := vk_api.ParseResponseUrl(r.URL.String())

fmt.Println(accessToken)
fmt.Println(userId)
fmt.Println(expiresIn)

答案1

得分: 2

主要代码如下:

package main

import (
	"fmt"
	"github.com/go-martini/martini"
	"github.com/yanple/vk_api"
	"net/http"
)

var api vk_api.Api

func prepareMartini() *martini.ClassicMartini {
	m := martini.Classic()

	m.Get("/vk/auth", func(w http.ResponseWriter, r *http.Request) {
		var api vk_api.Api
		authUrl, err := api.GetAuthUrl("http://localhost:3000/vk/token", "token", "2756549", "wall,offline")

		fmt.Println(authUrl)
		if err != nil {
			panic(err)
		}

		http.Redirect(w, r, authUrl, http.StatusFound)
	})

	m.Get("/vk/token", func(w http.ResponseWriter, r *http.Request) {
		accessToken, userId, expiresIn, err := vk_api.ParseResponseUrl(r.URL.String())
		if err != nil {
			panic(err)
		}
		fmt.Println(accessToken)
		fmt.Println(userId)
		fmt.Println(expiresIn)
	})
	return m
}

func main() {
	prepareMartini().Run()
}

对于 VK 设置,你需要像下面这个截图一样添加你的域名:

社交网络 VK 的认证与 Martini

之后,你将被重定向到 http://localhost:3000/vk/token#access_token=some_token&expires_in=0&user_id=0000000

但是我不确定你将如何通过 "ParseResponseUrl" 解析 URL,因为 VK 给你的是 "fragment URL"。

"fragment URL" 不会通过 HTTP 发送到服务器,我认为这可能是个问题。

英文:
package main

import (
	"fmt"
	"github.com/go-martini/martini"
	"github.com/yanple/vk_api"
	"net/http"
)

var api vk_api.Api

func prepareMartini() *martini.ClassicMartini {
	m := martini.Classic()

	m.Get("/vk/auth", func(w http.ResponseWriter, r *http.Request) {
		var api vk_api.Api
		authUrl, err := api.GetAuthUrl("http://localhost:3000/vk/token", "token", "2756549", "wall,offline")

		fmt.Println(authUrl)
		if err != nil {
			panic(err)
		}

		http.Redirect(w, r, authUrl, http.StatusFound)
	})

	m.Get("/vk/token", func(w http.ResponseWriter, r *http.Request) {
		accessToken, userId, expiresIn, err := vk_api.ParseResponseUrl(r.URL.String())
		if err != nil {
			panic(err)
		}
		fmt.Println(accessToken)
		fmt.Println(userId)
		fmt.Println(expiresIn)
	})
	return m
}

func main() {
	prepareMartini().Run()
}

for you VK settings you have to add your domain like on this screenshot

社交网络 VK 的认证与 Martini

After that you will be redirected to http://localhost:3000/vk/token#access_token=some_token&expires_in=0&user_id=0000000

but I'm not sure how you will Parse url via "ParseResponseUrl" because vk get to you "fragment url".

Fragment url is not sending to serve via HTTP - I think that could be a problem.

答案2

得分: 1

感谢回答,
我添加了 示例 @qwertmax,并修复了解析 URL 片段的错误。请更新包并查看示例。

package main

// 感谢 @qwertmax 提供的示例
// (http://stackoverflow.com/questions/29359907/social-network-vk-auth-with-martini)

import (
    "log"
    "github.com/go-martini/martini"
    "github.com/yanple/vk_api"
    "net/http"
)

var api vk_api.Api

func prepareMartini() *martini.ClassicMartini {
    m := martini.Classic()

    m.Get("/vk/auth", func(w http.ResponseWriter, r *http.Request) {
        authUrl, err := api.GetAuthUrl(
            "http://localhost:3000/vk/token",
            "app client id",
            "wall,offline")

        if err != nil {
            panic(err)
        }

        http.Redirect(w, r, authUrl, http.StatusFound)
    })

    m.Get("/vk/token", func(w http.ResponseWriter, r *http.Request) {
        code := r.URL.Query().Get("code")

        err := api.OAuth(
            "http://localhost:3000/vk/token", // redirect uri
            "app secret key",
            "app client id",
            code)
        if err != nil {
            panic(err)
        }
        http.Redirect(w, r, "/", http.StatusFound)
    })

    m.Get("/", func(w http.ResponseWriter, r *http.Request) string {
        if api.AccessToken == "" {
            return "<a href='/vk/auth'>Авторизоваться</a>"
        }

        // Api have: AccessToken, UserId, ExpiresIn
        log.Println("[LOG] martini.go:48 ->", api.AccessToken)

        // Make query
        params := make(map[string]string)
        params["domain"] = "yanple"
        params["count"] = "1"

        strResp, err := api.Request("wall.get", params)
        if err != nil {
            panic(err)
        }
        return strResp
    })
    return m
}

func main() {
    prepareMartini().Run()
}

**更新 1:**
使用命令更新您的包: **go get -u github.com/yanple/vk_api**
感谢您的评论

<details>
<summary>英文:</summary>

Thanks for answer,
I added [example](https://github.com/yanple/vk_api/blob/master/examples/martini.go) @qwertmax and fixed bug for parse fragment of url. Please update package and see example.




    package main
    // Thanks @qwertmax for this example
    // (http://stackoverflow.com/questions/29359907/social-network-vk-auth-with-martini)
    
    
    import (
        &quot;log&quot;
        &quot;github.com/go-martini/martini&quot;
        &quot;github.com/yanple/vk_api&quot;
        &quot;net/http&quot;
    )
    
    var api vk_api.Api
    
    func prepareMartini() *martini.ClassicMartini {
        m := martini.Classic()
    
        m.Get(&quot;/vk/auth&quot;, func(w http.ResponseWriter, r *http.Request) {
            authUrl, err := api.GetAuthUrl(
            &quot;http://localhost:3000/vk/token&quot;,
            &quot;app client id&quot;,
            &quot;wall,offline&quot;)
    
            if err != nil {
                panic(err)
            }
    
            http.Redirect(w, r, authUrl, http.StatusFound)
        })
    
        m.Get(&quot;/vk/token&quot;, func(w http.ResponseWriter, r *http.Request) {
            code := r.URL.Query().Get(&quot;code&quot;)
    
            err := api.OAuth(
            &quot;http://localhost:3000/vk/token&quot;, // redirect uri
            &quot;app secret key&quot;,
            &quot;app client id&quot;,
            code)
            if err != nil {
                panic(err)
            }
            http.Redirect(w, r, &quot;/&quot;, http.StatusFound)
        })
    
        m.Get(&quot;/&quot;, func(w http.ResponseWriter, r *http.Request) string {
            if api.AccessToken == &quot;&quot; {
                return &quot;&lt;a href=&#39;/vk/auth&#39;&gt;Авторизоваться&lt;/a&gt;&quot;
            }
    
            // Api have: AccessToken, UserId, ExpiresIn
            log.Println(&quot;[LOG] martini.go:48 -&gt;&quot;, api.AccessToken)
    
            // Make query
            params := make(map[string]string)
            params[&quot;domain&quot;] = &quot;yanple&quot;
            params[&quot;count&quot;] = &quot;1&quot;
    
            strResp, err := api.Request(&quot;wall.get&quot;, params)
            if err != nil {
                panic(err)
            }
            return strResp
        })
        return m
    }
    
    func main() {
        prepareMartini().Run()
    }

**Update 1:**
  Update your package with command: **go get -u github.com/yanple/vk_api**
  Thanks for the comment.

</details>



# 答案3
**得分**: 0

在包文档中`YourRedirectFunc`被用作在你的特定情况下重定向请求的实际方法的占位符例如它可以是`http.Redirect``getCurrentUrl`也是同样的情况

实际上你提供的示例应该写成两个处理程序用于你的martini实例

```go
// 这个处理程序将请求重定向到vkontakte系统,该系统将执行身份验证,然后将请求重定向到我们在GetAuthUrl方法的第一个参数中提供的URL(由第二个处理程序处理)
m.Get("/vk/auth", func(w http.ResponseWriter, r *http.Request) {
    var api vk_api.Api
    authUrl, err := api.GetAuthUrl("domain.com/vk/token", "token", "4672050", "wall,offline")
    if err != nil {
        panic(err)
    }

    http.Redirect(w, r, authUrl, http.Found)
})

// 这个处理程序从vkontakte api获取实际的身份验证信息。你可以获取访问令牌、用户ID和身份验证会话的过期日期。你可以根据需要对它们进行任何操作,通常是将它们存储在会话中,以便以后使用访问令牌获取实际的信息。
m.Get("/vk/token", func(w http.ResponseWriter, r *http.Request) {
    accessToken, userId, expiresIn, err := vk_api.ParseResponseUrl(r.URL.String())
    if err != nil {
        panic(err)
    }
})
英文:

In the package documentation, YourRedirectFunc is intended as placeholder for the actual method used to redirect a request in your particular case. It could be http.Redirect for example. Same for getCurrentUrl.

In fact, the example you linked to should be written as two handlers for your martini instance:

// This handler redirect the request to the vkontact system, which
// will perform the authentification then redirect the request to
// the URL we gave as the first paraemeter of the GetAuthUrl method
// (treated by the second handler)
m.Get(&quot;/vk/auth&quot;, func(w http.ResponseWriter, r *http.Request) {
var api vk_api.Api
authUrl, err := api.GetAuthUrl(&quot;domain.com/vk/token&quot;, &quot;token&quot;, &quot;4672050&quot;, &quot;wall,offline&quot;)
if err != nil {
panic(err)
}
http.Redirect(w, r, authUrl, http.Found)
})
// This handler is the one that get the actual authentification 
// information from the vkontact api. You get the access token,
// userid and expiration date of the authentification session. 
// You can do whatever you want with them, generally storing them 
// in session to be able to get the actual informations later using
// the access token.
m.Get(&quot;/vk/token&quot;, func(w http.ResponseWriter, r *http.Request) {
accessToken, userId, expiresIn, err := vk_api.ParseResponseUrl(r.URL.String())
if err != nil {
panic(err)
}
})

huangapple
  • 本文由 发表于 2015年3月31日 11:04:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/29359907.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定