英文:
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 设置,你需要像下面这个截图一样添加你的域名:

之后,你将被重定向到 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

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 (
"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()
}
**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("/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)
})
// 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)
}
})
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论