mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 10:41:03 +01:00
Add OAuth2 integration example, have fun! https://github.com/iris-contrib/community-board/issues/4
Former-commit-id: e4f9dfbdfe16c9ca1ad84ac5a844a5d060fb3b5e
This commit is contained in:
parent
6282a71a6f
commit
5e00c50c37
|
@ -163,7 +163,7 @@ $ rizla main.go
|
|||
<details>
|
||||
<summary>Legends</summary>
|
||||
|
||||
I'm sorry for taking this personally but I really need to thanks each one of them because they stood up [♡](https://github.com/kataras/iris#support) for me when others trying to "bullying" my personality in order to deflame Iris.
|
||||
I'm sorry for taking this personally but I really need to thank each one of them because they stood up [♡](https://github.com/kataras/iris#support) for me when others tried to "bullying" my personality in order to deflame Iris.
|
||||
|
||||
All of us should read and respect the official [golang](https://golang.org/conduct) and [iris](https://github.com/iris-contrib/community-board/blob/master/CODE-OF-CONDUCT.md) community **Code of Conduct**. This type of commitment and communication is the way of making Go great.
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ It doesn't contains "best ways" neither explains all its features. It's just a s
|
|||
* [Request Logger](beginner/request-logger/main.go)
|
||||
* [Basic Authentication](beginner/basicauth/main.go)
|
||||
* [Level: Intermediate](intermediate)
|
||||
* [OAUth2](intermediate/oauth2/main.go)
|
||||
* [Transactions](intermediate/transactions/main.go)
|
||||
* [HTTP Testing](intermediate/httptest/main_test.go)
|
||||
* [Watch & Compile Typescript source files](intermediate/typescript/main.go)
|
||||
|
|
409
_examples/intermediate/oauth2/main.go
Normal file
409
_examples/intermediate/oauth2/main.go
Normal file
|
@ -0,0 +1,409 @@
|
|||
package main
|
||||
|
||||
// Any OAuth2 (even the pure golang/x/net/oauth2) package
|
||||
// can be used with Iris but at this example we will see the markbates' goth:
|
||||
//
|
||||
// $ go get github.com/markbates/goth/...
|
||||
//
|
||||
// This OAuth2 example works with sessions, so we will need
|
||||
// to attach a session manager.
|
||||
// Optionally: for even more secure session values,
|
||||
// developers can use any third-party package to add a custom cookie encoder/decoder.
|
||||
// At this example we will use the gorilla's securecookie:
|
||||
//
|
||||
// $ go get github.com/gorilla/securecookie
|
||||
// Example of securecookie can be found at "sessions/securecookie" example folder.
|
||||
|
||||
// Notes:
|
||||
// The whole example is converted by markbates/goth/example/main.go.
|
||||
// It's tested with my own TWITTER application and it worked, even for localhost.
|
||||
// I guess that everything else works as expected, all bugs reported by goth library's community
|
||||
// are fixed in the time I wrote that example, have fun!
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/sessions"
|
||||
"github.com/kataras/iris/view"
|
||||
|
||||
"github.com/gorilla/securecookie" // optionally, used for session's encoder/decoder
|
||||
|
||||
"github.com/markbates/goth"
|
||||
"github.com/markbates/goth/providers/amazon"
|
||||
"github.com/markbates/goth/providers/auth0"
|
||||
"github.com/markbates/goth/providers/bitbucket"
|
||||
"github.com/markbates/goth/providers/box"
|
||||
"github.com/markbates/goth/providers/dailymotion"
|
||||
"github.com/markbates/goth/providers/deezer"
|
||||
"github.com/markbates/goth/providers/digitalocean"
|
||||
"github.com/markbates/goth/providers/discord"
|
||||
"github.com/markbates/goth/providers/dropbox"
|
||||
"github.com/markbates/goth/providers/facebook"
|
||||
"github.com/markbates/goth/providers/fitbit"
|
||||
"github.com/markbates/goth/providers/github"
|
||||
"github.com/markbates/goth/providers/gitlab"
|
||||
"github.com/markbates/goth/providers/gplus"
|
||||
"github.com/markbates/goth/providers/heroku"
|
||||
"github.com/markbates/goth/providers/instagram"
|
||||
"github.com/markbates/goth/providers/intercom"
|
||||
"github.com/markbates/goth/providers/lastfm"
|
||||
"github.com/markbates/goth/providers/linkedin"
|
||||
"github.com/markbates/goth/providers/meetup"
|
||||
"github.com/markbates/goth/providers/onedrive"
|
||||
"github.com/markbates/goth/providers/openidConnect"
|
||||
"github.com/markbates/goth/providers/paypal"
|
||||
"github.com/markbates/goth/providers/salesforce"
|
||||
"github.com/markbates/goth/providers/slack"
|
||||
"github.com/markbates/goth/providers/soundcloud"
|
||||
"github.com/markbates/goth/providers/spotify"
|
||||
"github.com/markbates/goth/providers/steam"
|
||||
"github.com/markbates/goth/providers/stripe"
|
||||
"github.com/markbates/goth/providers/twitch"
|
||||
"github.com/markbates/goth/providers/twitter"
|
||||
"github.com/markbates/goth/providers/uber"
|
||||
"github.com/markbates/goth/providers/wepay"
|
||||
"github.com/markbates/goth/providers/xero"
|
||||
"github.com/markbates/goth/providers/yahoo"
|
||||
"github.com/markbates/goth/providers/yammer"
|
||||
)
|
||||
|
||||
// These are some function helpers that you may use if you want
|
||||
|
||||
// GetProviderName is a function used to get the name of a provider
|
||||
// for a given request. By default, this provider is fetched from
|
||||
// the URL query string. If you provide it in a different way,
|
||||
// assign your own function to this variable that returns the provider
|
||||
// name for your request.
|
||||
var GetProviderName = func(ctx context.Context) (string, error) {
|
||||
// try to get it from the url param "provider"
|
||||
if p := ctx.URLParam("provider"); p != "" {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// try to get it from the url PATH parameter "{provider} or :provider or {provider:string} or {provider:alphabetical}"
|
||||
if p := ctx.Params().Get("provider"); p != "" {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// try to get it from context's per-request storage
|
||||
if p := ctx.Values().GetString("provider"); p != "" {
|
||||
return p, nil
|
||||
}
|
||||
// if not found then return an empty string with the corresponding error
|
||||
return "", errors.New("you must select a provider")
|
||||
}
|
||||
|
||||
/*
|
||||
BeginAuthHandler is a convienence handler for starting the authentication process.
|
||||
It expects to be able to get the name of the provider from the query parameters
|
||||
as either "provider" or ":provider".
|
||||
|
||||
BeginAuthHandler will redirect the user to the appropriate authentication end-point
|
||||
for the requested provider.
|
||||
|
||||
See https://github.com/markbates/goth/examples/main.go to see this in action.
|
||||
*/
|
||||
func BeginAuthHandler(ctx context.Context) {
|
||||
url, err := GetAuthURL(ctx)
|
||||
if err != nil {
|
||||
ctx.StatusCode(iris.StatusBadRequest)
|
||||
ctx.Writef("%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Redirect(url, iris.StatusTemporaryRedirect)
|
||||
}
|
||||
|
||||
/*
|
||||
GetAuthURL starts the authentication process with the requested provided.
|
||||
It will return a URL that should be used to send users to.
|
||||
|
||||
It expects to be able to get the name of the provider from the query parameters
|
||||
as either "provider" or ":provider" or from the context's value of "provider" key.
|
||||
|
||||
I would recommend using the BeginAuthHandler instead of doing all of these steps
|
||||
yourself, but that's entirely up to you.
|
||||
*/
|
||||
func GetAuthURL(ctx context.Context) (string, error) {
|
||||
providerName, err := GetProviderName(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
provider, err := goth.GetProvider(providerName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
sess, err := provider.BeginAuth(SetState(ctx))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
url, err := sess.GetAuthURL()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
ctx.Session().Set(providerName, sess.Marshal())
|
||||
return url, nil
|
||||
}
|
||||
|
||||
// SetState sets the state string associated with the given request.
|
||||
// If no state string is associated with the request, one will be generated.
|
||||
// This state is sent to the provider and can be retrieved during the
|
||||
// callback.
|
||||
var SetState = func(ctx context.Context) string {
|
||||
state := ctx.URLParam("state")
|
||||
if len(state) > 0 {
|
||||
return state
|
||||
}
|
||||
|
||||
return "state"
|
||||
|
||||
}
|
||||
|
||||
// GetState gets the state returned by the provider during the callback.
|
||||
// This is used to prevent CSRF attacks, see
|
||||
// http://tools.ietf.org/html/rfc6749#section-10.12
|
||||
var GetState = func(ctx context.Context) string {
|
||||
return ctx.URLParam("state")
|
||||
}
|
||||
|
||||
/*
|
||||
CompleteUserAuth does what it says on the tin. It completes the authentication
|
||||
process and fetches all of the basic information about the user from the provider.
|
||||
|
||||
It expects to be able to get the name of the provider from the query parameters
|
||||
as either "provider" or ":provider".
|
||||
|
||||
See https://github.com/markbates/goth/examples/main.go to see this in action.
|
||||
*/
|
||||
var CompleteUserAuth = func(ctx context.Context) (goth.User, error) {
|
||||
providerName, err := GetProviderName(ctx)
|
||||
if err != nil {
|
||||
return goth.User{}, err
|
||||
}
|
||||
|
||||
provider, err := goth.GetProvider(providerName)
|
||||
if err != nil {
|
||||
return goth.User{}, err
|
||||
}
|
||||
|
||||
value := ctx.Session().GetString(providerName)
|
||||
if value == "" {
|
||||
return goth.User{}, errors.New("session value for " + providerName + " not found")
|
||||
}
|
||||
|
||||
sess, err := provider.UnmarshalSession(value)
|
||||
if err != nil {
|
||||
return goth.User{}, err
|
||||
}
|
||||
|
||||
user, err := provider.FetchUser(sess)
|
||||
if err == nil {
|
||||
// user can be found with existing session data
|
||||
return user, err
|
||||
}
|
||||
|
||||
// get new token and retry fetch
|
||||
_, err = sess.Authorize(provider, ctx.Request().URL.Query())
|
||||
if err != nil {
|
||||
return goth.User{}, err
|
||||
}
|
||||
|
||||
ctx.Session().Set(providerName, sess.Marshal())
|
||||
return provider.FetchUser(sess)
|
||||
}
|
||||
|
||||
// Logout invalidates a user session.
|
||||
func Logout(ctx context.Context) error {
|
||||
providerName, err := GetProviderName(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx.Session().Delete(providerName)
|
||||
return nil
|
||||
}
|
||||
|
||||
// End of the "some function helpers".
|
||||
|
||||
func main() {
|
||||
goth.UseProviders(
|
||||
twitter.New(os.Getenv("TWITTER_KEY"), os.Getenv("TWITTER_SECRET"), "http://localhost:3000/auth/twitter/callback"),
|
||||
// If you'd like to use authenticate instead of authorize in Twitter provider, use this instead.
|
||||
// twitter.NewAuthenticate(os.Getenv("TWITTER_KEY"), os.Getenv("TWITTER_SECRET"), "http://localhost:3000/auth/twitter/callback"),
|
||||
|
||||
facebook.New(os.Getenv("FACEBOOK_KEY"), os.Getenv("FACEBOOK_SECRET"), "http://localhost:3000/auth/facebook/callback"),
|
||||
fitbit.New(os.Getenv("FITBIT_KEY"), os.Getenv("FITBIT_SECRET"), "http://localhost:3000/auth/fitbit/callback"),
|
||||
gplus.New(os.Getenv("GPLUS_KEY"), os.Getenv("GPLUS_SECRET"), "http://localhost:3000/auth/gplus/callback"),
|
||||
github.New(os.Getenv("GITHUB_KEY"), os.Getenv("GITHUB_SECRET"), "http://localhost:3000/auth/github/callback"),
|
||||
spotify.New(os.Getenv("SPOTIFY_KEY"), os.Getenv("SPOTIFY_SECRET"), "http://localhost:3000/auth/spotify/callback"),
|
||||
linkedin.New(os.Getenv("LINKEDIN_KEY"), os.Getenv("LINKEDIN_SECRET"), "http://localhost:3000/auth/linkedin/callback"),
|
||||
lastfm.New(os.Getenv("LASTFM_KEY"), os.Getenv("LASTFM_SECRET"), "http://localhost:3000/auth/lastfm/callback"),
|
||||
twitch.New(os.Getenv("TWITCH_KEY"), os.Getenv("TWITCH_SECRET"), "http://localhost:3000/auth/twitch/callback"),
|
||||
dropbox.New(os.Getenv("DROPBOX_KEY"), os.Getenv("DROPBOX_SECRET"), "http://localhost:3000/auth/dropbox/callback"),
|
||||
digitalocean.New(os.Getenv("DIGITALOCEAN_KEY"), os.Getenv("DIGITALOCEAN_SECRET"), "http://localhost:3000/auth/digitalocean/callback", "read"),
|
||||
bitbucket.New(os.Getenv("BITBUCKET_KEY"), os.Getenv("BITBUCKET_SECRET"), "http://localhost:3000/auth/bitbucket/callback"),
|
||||
instagram.New(os.Getenv("INSTAGRAM_KEY"), os.Getenv("INSTAGRAM_SECRET"), "http://localhost:3000/auth/instagram/callback"),
|
||||
intercom.New(os.Getenv("INTERCOM_KEY"), os.Getenv("INTERCOM_SECRET"), "http://localhost:3000/auth/intercom/callback"),
|
||||
box.New(os.Getenv("BOX_KEY"), os.Getenv("BOX_SECRET"), "http://localhost:3000/auth/box/callback"),
|
||||
salesforce.New(os.Getenv("SALESFORCE_KEY"), os.Getenv("SALESFORCE_SECRET"), "http://localhost:3000/auth/salesforce/callback"),
|
||||
amazon.New(os.Getenv("AMAZON_KEY"), os.Getenv("AMAZON_SECRET"), "http://localhost:3000/auth/amazon/callback"),
|
||||
yammer.New(os.Getenv("YAMMER_KEY"), os.Getenv("YAMMER_SECRET"), "http://localhost:3000/auth/yammer/callback"),
|
||||
onedrive.New(os.Getenv("ONEDRIVE_KEY"), os.Getenv("ONEDRIVE_SECRET"), "http://localhost:3000/auth/onedrive/callback"),
|
||||
|
||||
//Pointed localhost.com to http://localhost:3000/auth/yahoo/callback through proxy as yahoo
|
||||
// does not allow to put custom ports in redirection uri
|
||||
yahoo.New(os.Getenv("YAHOO_KEY"), os.Getenv("YAHOO_SECRET"), "http://localhost.com"),
|
||||
slack.New(os.Getenv("SLACK_KEY"), os.Getenv("SLACK_SECRET"), "http://localhost:3000/auth/slack/callback"),
|
||||
stripe.New(os.Getenv("STRIPE_KEY"), os.Getenv("STRIPE_SECRET"), "http://localhost:3000/auth/stripe/callback"),
|
||||
wepay.New(os.Getenv("WEPAY_KEY"), os.Getenv("WEPAY_SECRET"), "http://localhost:3000/auth/wepay/callback", "view_user"),
|
||||
//By default paypal production auth urls will be used, please set PAYPAL_ENV=sandbox as environment variable for testing
|
||||
//in sandbox environment
|
||||
paypal.New(os.Getenv("PAYPAL_KEY"), os.Getenv("PAYPAL_SECRET"), "http://localhost:3000/auth/paypal/callback"),
|
||||
steam.New(os.Getenv("STEAM_KEY"), "http://localhost:3000/auth/steam/callback"),
|
||||
heroku.New(os.Getenv("HEROKU_KEY"), os.Getenv("HEROKU_SECRET"), "http://localhost:3000/auth/heroku/callback"),
|
||||
uber.New(os.Getenv("UBER_KEY"), os.Getenv("UBER_SECRET"), "http://localhost:3000/auth/uber/callback"),
|
||||
soundcloud.New(os.Getenv("SOUNDCLOUD_KEY"), os.Getenv("SOUNDCLOUD_SECRET"), "http://localhost:3000/auth/soundcloud/callback"),
|
||||
gitlab.New(os.Getenv("GITLAB_KEY"), os.Getenv("GITLAB_SECRET"), "http://localhost:3000/auth/gitlab/callback"),
|
||||
dailymotion.New(os.Getenv("DAILYMOTION_KEY"), os.Getenv("DAILYMOTION_SECRET"), "http://localhost:3000/auth/dailymotion/callback", "email"),
|
||||
deezer.New(os.Getenv("DEEZER_KEY"), os.Getenv("DEEZER_SECRET"), "http://localhost:3000/auth/deezer/callback", "email"),
|
||||
discord.New(os.Getenv("DISCORD_KEY"), os.Getenv("DISCORD_SECRET"), "http://localhost:3000/auth/discord/callback", discord.ScopeIdentify, discord.ScopeEmail),
|
||||
meetup.New(os.Getenv("MEETUP_KEY"), os.Getenv("MEETUP_SECRET"), "http://localhost:3000/auth/meetup/callback"),
|
||||
|
||||
//Auth0 allocates domain per customer, a domain must be provided for auth0 to work
|
||||
auth0.New(os.Getenv("AUTH0_KEY"), os.Getenv("AUTH0_SECRET"), "http://localhost:3000/auth/auth0/callback", os.Getenv("AUTH0_DOMAIN")),
|
||||
xero.New(os.Getenv("XERO_KEY"), os.Getenv("XERO_SECRET"), "http://localhost:3000/auth/xero/callback"),
|
||||
)
|
||||
|
||||
// OpenID Connect is based on OpenID Connect Auto Discovery URL (https://openid.net/specs/openid-connect-discovery-1_0-17.html)
|
||||
// because the OpenID Connect provider initialize it self in the New(), it can return an error which should be handled or ignored
|
||||
// ignore the error for now
|
||||
openidConnect, _ := openidConnect.New(os.Getenv("OPENID_CONNECT_KEY"), os.Getenv("OPENID_CONNECT_SECRET"), "http://localhost:3000/auth/openid-connect/callback", os.Getenv("OPENID_CONNECT_DISCOVERY_URL"))
|
||||
if openidConnect != nil {
|
||||
goth.UseProviders(openidConnect)
|
||||
}
|
||||
|
||||
m := make(map[string]string)
|
||||
m["amazon"] = "Amazon"
|
||||
m["bitbucket"] = "Bitbucket"
|
||||
m["box"] = "Box"
|
||||
m["dailymotion"] = "Dailymotion"
|
||||
m["deezer"] = "Deezer"
|
||||
m["digitalocean"] = "Digital Ocean"
|
||||
m["discord"] = "Discord"
|
||||
m["dropbox"] = "Dropbox"
|
||||
m["facebook"] = "Facebook"
|
||||
m["fitbit"] = "Fitbit"
|
||||
m["github"] = "Github"
|
||||
m["gitlab"] = "Gitlab"
|
||||
m["soundcloud"] = "SoundCloud"
|
||||
m["spotify"] = "Spotify"
|
||||
m["steam"] = "Steam"
|
||||
m["stripe"] = "Stripe"
|
||||
m["twitch"] = "Twitch"
|
||||
m["uber"] = "Uber"
|
||||
m["wepay"] = "Wepay"
|
||||
m["yahoo"] = "Yahoo"
|
||||
m["yammer"] = "Yammer"
|
||||
m["gplus"] = "Google Plus"
|
||||
m["heroku"] = "Heroku"
|
||||
m["instagram"] = "Instagram"
|
||||
m["intercom"] = "Intercom"
|
||||
m["lastfm"] = "Last FM"
|
||||
m["linkedin"] = "Linkedin"
|
||||
m["onedrive"] = "Onedrive"
|
||||
m["paypal"] = "Paypal"
|
||||
m["twitter"] = "Twitter"
|
||||
m["salesforce"] = "Salesforce"
|
||||
m["slack"] = "Slack"
|
||||
m["meetup"] = "Meetup.com"
|
||||
m["auth0"] = "Auth0"
|
||||
m["openid-connect"] = "OpenID Connect"
|
||||
m["xero"] = "Xero"
|
||||
|
||||
var keys []string
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
providerIndex := &ProviderIndex{Providers: keys, ProvidersMap: m}
|
||||
|
||||
// create our app,
|
||||
// set a view
|
||||
// set sessions
|
||||
// and setup the router for the showcase
|
||||
app := iris.New()
|
||||
|
||||
// attach and build our templates
|
||||
app.AttachView(view.HTML("./templates", ".html"))
|
||||
|
||||
// attach a session manager
|
||||
cookieName := "mycustomsessionid"
|
||||
// AES only supports key sizes of 16, 24 or 32 bytes.
|
||||
// You either need to provide exactly that amount or you derive the key from what you type in.
|
||||
hashKey := []byte("the-big-and-secret-fash-key-here")
|
||||
blockKey := []byte("lot-secret-of-characters-big-too")
|
||||
secureCookie := securecookie.New(hashKey, blockKey)
|
||||
sessManager := sessions.New(sessions.Config{
|
||||
Cookie: cookieName,
|
||||
Encode: secureCookie.Encode,
|
||||
Decode: secureCookie.Decode,
|
||||
})
|
||||
app.AttachSessionManager(sessManager)
|
||||
|
||||
// start of the router
|
||||
|
||||
app.Get("/auth/{provider}/callback", func(ctx context.Context) {
|
||||
|
||||
user, err := CompleteUserAuth(ctx)
|
||||
if err != nil {
|
||||
ctx.StatusCode(iris.StatusInternalServerError)
|
||||
ctx.Writef("%v", err)
|
||||
return
|
||||
}
|
||||
ctx.ViewData("", user)
|
||||
if err := ctx.View("user.html"); err != nil {
|
||||
ctx.Writef("%v", err)
|
||||
}
|
||||
})
|
||||
|
||||
app.Get("/logout/{provider}", func(ctx context.Context) {
|
||||
Logout(ctx)
|
||||
ctx.Redirect("/", iris.StatusTemporaryRedirect)
|
||||
})
|
||||
|
||||
app.Get("/auth/{provider}", func(ctx context.Context) {
|
||||
// try to get the user without re-authenticating
|
||||
if gothUser, err := CompleteUserAuth(ctx); err == nil {
|
||||
ctx.ViewData("", gothUser)
|
||||
if err := ctx.View("user.html"); err != nil {
|
||||
ctx.Writef("%v", err)
|
||||
}
|
||||
} else {
|
||||
BeginAuthHandler(ctx)
|
||||
}
|
||||
})
|
||||
|
||||
app.Get("/", func(ctx context.Context) {
|
||||
|
||||
ctx.ViewData("", providerIndex)
|
||||
|
||||
if err := ctx.View("index.html"); err != nil {
|
||||
ctx.Writef("%v", err)
|
||||
}
|
||||
})
|
||||
|
||||
// http://localhost:3000
|
||||
app.Run(iris.Addr("localhost:3000"))
|
||||
}
|
||||
|
||||
type ProviderIndex struct {
|
||||
Providers []string
|
||||
ProvidersMap map[string]string
|
||||
}
|
3
_examples/intermediate/oauth2/templates/index.html
Normal file
3
_examples/intermediate/oauth2/templates/index.html
Normal file
|
@ -0,0 +1,3 @@
|
|||
{{range $key,$value:=.Providers}}
|
||||
<p><a href="/auth/{{$value}}">Log in with {{index $.ProvidersMap $value}}</a></p>
|
||||
{{end}}
|
11
_examples/intermediate/oauth2/templates/user.html
Normal file
11
_examples/intermediate/oauth2/templates/user.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
<p><a href="/logout/{{.Provider}}">logout</a></p>
|
||||
<p>Name: {{.Name}} [{{.LastName}}, {{.FirstName}}]</p>
|
||||
<p>Email: {{.Email}}</p>
|
||||
<p>NickName: {{.NickName}}</p>
|
||||
<p>Location: {{.Location}}</p>
|
||||
<p>AvatarURL: {{.AvatarURL}} <img src="{{.AvatarURL}}"></p>
|
||||
<p>Description: {{.Description}}</p>
|
||||
<p>UserID: {{.UserID}}</p>
|
||||
<p>AccessToken: {{.AccessToken}}</p>
|
||||
<p>ExpiresAt: {{.ExpiresAt}}</p>
|
||||
<p>RefreshToken: {{.RefreshToken}}</p>
|
|
@ -1,13 +1,16 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
// developers can use any library to add a custom cookie encoder/decoder.
|
||||
// At this example we use the gorilla's securecookie library:
|
||||
"github.com/gorilla/securecookie"
|
||||
// At this example we use the gorilla's securecookie package:
|
||||
// $ go get github.com/gorilla/securecookie
|
||||
// $ go run main.go
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/sessions"
|
||||
|
||||
"github.com/gorilla/securecookie"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
|
Loading…
Reference in New Issue
Block a user