README ¶
Auth
Auth is a modular authentication system for web development in Golang, it provides different authentication backends to accelerate your development.
Currently Auth has database password, github, google, facebook, twitter authentication support, and it is fairly easy to add other support based on Auth's Provider interface
Quick Start
Auth aims to provide an easy to use authentication system that don't require much developer's effort.
To use it, basic flow is:
- Initialize Auth with configuration
- Register some providers
- Register it into router
Here is an example:
package main
import (
"github.com/XUJiahua/auth"
"github.com/XUJiahua/auth/auth_identity"
"github.com/XUJiahua/auth/providers/github"
"github.com/XUJiahua/auth/providers/google"
"github.com/XUJiahua/auth/providers/password"
"github.com/XUJiahua/auth/providers/facebook"
"github.com/XUJiahua/auth/providers/twitter"
"github.com/qor/session/manager"
_ "github.com/mattn/go-sqlite3"
"net/http"
)
var (
// Initialize gorm DB
gormDB, _ = gorm.Open("sqlite3", "sample.db")
// Initialize Auth with configuration
Auth = auth.New(&auth.Config{
DB: gormDB,
})
)
func init() {
// Migrate AuthIdentity model, AuthIdentity will be used to save auth info, like username/password, oauth token, you could change that.
gormDB.AutoMigrate(&auth_identity.AuthIdentity{})
// Register Auth providers
// Allow use username/password
Auth.RegisterProvider(password.New(&password.Config{}))
// Allow use Github
Auth.RegisterProvider(github.New(&github.Config{
ClientID: "github client id",
ClientSecret: "github client secret",
}))
// Allow use Google
Auth.RegisterProvider(google.New(&google.Config{
ClientID: "google client id",
ClientSecret: "google client secret",
AllowedDomains: []string{}, // Accept all domains, instead you can pass a whitelist of acceptable domains
}))
// Allow use Facebook
Auth.RegisterProvider(facebook.New(&facebook.Config{
ClientID: "facebook client id",
ClientSecret: "facebook client secret",
}))
// Allow use Twitter
Auth.RegisterProvider(twitter.New(&twitter.Config{
ClientID: "twitter client id",
ClientSecret: "twitter client secret",
}))
}
func main() {
mux := http.NewServeMux()
// Mount Auth to Router
mux.Handle("/auth/", Auth.NewServeMux())
http.ListenAndServe(":9000", manager.SessionManager.Middleware(mux))
}
That's it, then you could goto http://127.0.0.1:9000/auth/login
to try Auth features, like login, logout, register, forgot/change password...
And it could be even easier with Auth Themes, you could integrate Auth into your application with few line configurations.
Usage
Auth has many configurations that could be used to customize it for different usage, lets start from Auth's Config.
Models
Auth has two models, model AuthIdentityModel
is used to save login information, model UserModel
is used to save user information.
The reason we save auth and user info into two different models, as we want to be able to link a user to mutliple auth info records, so a user could have multiple ways to login.
If this is not required for you, you could just set those two models to same one or skip set UserModel
.
AuthIdentityModel
Different provider usually use different information to login, like provider password
use username/password, github
use github user ID, so for each provider, it will save those information into its own record.
You are not necessary to set AuthIdentityModel
, Auth has a default definition of AuthIdentityModel, in case of you want to change it, make sure you have auth_identity.Basic embedded, as Auth
assume you have same data structure in your database, so it could query/create records with SQL.
UserModel
By default, there is no UserModel
defined, even though, you still be able to use Auth
features, Auth
will return used auth info record as logged user.
But usually your application will have a User
model, after you set its value, when you register a new account from any provider, Auth will create/get a user with UserStorer
, and link its ID to the auth identity record.
Customize views
Auth using Render to render pages, you could refer it for how to register func maps, extend views paths, also be sure to refer BindataFS if you want to compile your application into a binary.
If you want to preprend view paths, you could add them to ViewPaths
, which would be helpful if you want to overwrite the default (ugly) login/register pages or develop auth themes like https://github.com/qor/auth_themes
Sending Emails
Auth using Mailer to send emails, by default, Auth will print emails to console, please configure it to send real one.
User Storer
Auth created a default UserStorer to get/save user based on your AuthIdentityModel
, UserModel
's definition, in case of you want to change it, you could implement your own User Storer
Session Storer
Auth also has a default way to handle sessions, flash messages, which could be overwrited by implementing Session Storer Interface.
By default, Auth is using session's default manager to save data into cookies, but in order to save cookies correctly, you have to register session's Middleware into your router, e.g:
func main() {
mux := http.NewServeMux()
// Register Router
mux.Handle("/auth/", Auth.NewServeMux())
http.ListenAndServe(":9000", manager.SessionManager.Middleware(mux))
}
Redirector
After some Auth actions, like logged, registered or confirmed, Auth will redirect user to some URL, you could configure which page to redirect with Redirector
, by default, will redirct to home page.
If you want to redirect to last visited page, redirect_back is for you, you could configure it and use it as the Redirector, like:
var RedirectBack = redirect_back.New(&redirect_back.Config{
SessionManager: manager.SessionManager,
IgnoredPrefixes: []string{"/auth"},
}
var Auth = auth.New(&auth.Config{
...
Redirector: auth.Redirector{RedirectBack},
})
BTW, to make it works correctly, redirect_back
need to save last visisted URL into session with session manager for each request, that's means, you need to mount redirect_back
, and SessionManager
's middleware into router.
http.ListenAndServe(":9000", manager.SessionManager.Middleware(RedirectBack.Middleware(mux)))
Advanced Usage
Auth Themes
In order to save more developer's effort, we have created some auth themes.
It usually has well designed pages, if you don't much custom requirements, you could just have few lines to make Auth system ready to use for your application, for example:
import "github.com/XUJiahua/auth_themes/clean"
var Auth = clean.New(&auth.Config{
DB: db.DB,
Render: config.View,
Mailer: config.Mailer,
UserModel: models.User{},
})
Check Auth Theme's document for How To use/create Auth themes
Authorization
Authentication
is the process of verifying who you are, Authorization
is the process of verifying that you have access to something.
Auth package not only provides Authentication
, but also Authorization
, please checkout authority for more details
Documentation ¶
Index ¶
- Constants
- Variables
- type Auth
- func (auth *Auth) AuthURL(pth string) string
- func (auth *Auth) GetCurrentUser(req *http.Request) interface{}
- func (auth *Auth) GetDB(request *http.Request) *gorm.DB
- func (auth *Auth) GetProvider(name string) Provider
- func (auth *Auth) GetProviders() (providers []Provider)
- func (auth *Auth) Login(w http.ResponseWriter, req *http.Request, claimer claims.ClaimerInterface) error
- func (auth *Auth) Logout(w http.ResponseWriter, req *http.Request)
- func (auth *Auth) NewServeMux() http.Handler
- func (auth *Auth) RegisterProvider(provider Provider)
- type Config
- type Context
- type Provider
- type Redirector
- type RedirectorInterface
- type Schema
- type SessionStorer
- func (sessionStorer *SessionStorer) Delete(w http.ResponseWriter, req *http.Request) error
- func (sessionStorer *SessionStorer) Flash(w http.ResponseWriter, req *http.Request, message session.Message) error
- func (sessionStorer *SessionStorer) Flashes(w http.ResponseWriter, req *http.Request) []session.Message
- func (sessionStorer *SessionStorer) Get(req *http.Request) (*claims.Claims, error)
- func (sessionStorer *SessionStorer) SignedToken(claims *claims.Claims) string
- func (sessionStorer *SessionStorer) Update(w http.ResponseWriter, req *http.Request, claims *claims.Claims) error
- func (sessionStorer *SessionStorer) ValidateClaims(tokenString string) (*claims.Claims, error)
- type SessionStorerInterface
- type UserStorer
- type UserStorerInterface
Constants ¶
const CurrentUser utils.ContextKey = "current_user"
CurrentUser context key to get current user from Request
Variables ¶
var ( // ErrInvalidPassword invalid password error ErrInvalidPassword = errors.New("invalid password") // ErrInvalidAccount invalid account error ErrInvalidAccount = errors.New("invalid account") ErrUnauthorized = errors.New("Unauthorized") )
var DefaultAssetHandler = func(context *Context) { asset := strings.TrimPrefix(context.Request.URL.Path, context.Auth.URLPrefix) if context.Request.Header.Get("If-Modified-Since") == cacheSince { context.Writer.WriteHeader(http.StatusNotModified) return } context.Writer.Header().Set("Last-Modified", cacheSince) if content, err := context.Config.Render.Asset(path.Join("/auth", asset)); err == nil { etag := fmt.Sprintf("%x", md5.Sum(content)) if context.Request.Header.Get("If-None-Match") == etag { context.Writer.WriteHeader(http.StatusNotModified) return } if ctype := mime.TypeByExtension(filepath.Ext(asset)); ctype != "" { context.Writer.Header().Set("Content-Type", ctype) } context.Writer.Header().Set("Cache-control", "private, must-revalidate, max-age=300") context.Writer.Header().Set("ETag", etag) context.Writer.Write(content) } else { http.NotFound(context.Writer, context.Request) } }
DefaultAssetHandler render auth asset file
var DefaultLoginHandler = func(context *Context, authorize func(*Context) (*claims.Claims, error)) { var ( req = context.Request w = context.Writer claims, err = authorize(context) ) if err == nil && claims != nil { context.SessionStorer.Flash(w, req, session.Message{Message: "logged"}) respondAfterLogged(claims, context) return } context.SessionStorer.Flash(w, req, session.Message{Message: template.HTML(err.Error()), Type: "error"}) responder.With("html", func() { context.Auth.Config.Render.Execute("auth/login", context, req, w) }).With([]string{"json"}, func() { }).Respond(context.Request) }
DefaultLoginHandler default login behaviour
var DefaultLogoutHandler = func(context *Context) {
context.SessionStorer.Delete(context.Writer, context.Request)
context.Auth.Redirector.Redirect(context.Writer, context.Request, "logout")
}
DefaultLogoutHandler default logout behaviour
var DefaultRegisterHandler = func(context *Context, register func(*Context) (*claims.Claims, error)) { var ( req = context.Request w = context.Writer claims, err = register(context) ) if err == nil && claims != nil { respondAfterLogged(claims, context) return } context.SessionStorer.Flash(w, req, session.Message{Message: template.HTML(err.Error()), Type: "error"}) responder.With("html", func() { context.Auth.Config.Render.Execute("auth/register", context, req, w) }).With([]string{"json"}, func() { }).Respond(context.Request) }
DefaultRegisterHandler default register behaviour
Functions ¶
This section is empty.
Types ¶
type Auth ¶
type Auth struct { *Config // Embed SessionStorer to match Authority's AuthInterface SessionStorerInterface // contains filtered or unexported fields }
Auth auth struct
func (*Auth) GetCurrentUser ¶
GetCurrentUser get current user from request
func (*Auth) GetProvider ¶
GetProvider get provider with name
func (*Auth) GetProviders ¶
GetProviders return registered providers
func (*Auth) Login ¶
func (auth *Auth) Login(w http.ResponseWriter, req *http.Request, claimer claims.ClaimerInterface) error
Login sign user in
func (*Auth) Logout ¶
func (auth *Auth) Logout(w http.ResponseWriter, req *http.Request)
Logout sign current user out
func (*Auth) NewServeMux ¶
NewServeMux generate http.Handler for auth
func (*Auth) RegisterProvider ¶
RegisterProvider register auth provider
type Config ¶
type Config struct { // Default Database, which will be used in Auth when do CRUD, you can change a request's DB isntance by setting request Context's value, refer https://github.com/qor/auth/blob/master/utils.go#L32 DB *gorm.DB // AuthIdentityModel a model used to save auth info, like email/password, OAuth token, linked user's ID, https://github.com/qor/auth/blob/master/auth_identity/auth_identity.go is the default implemention AuthIdentityModel interface{} // UserModel should be point of user struct's instance, it could be nil, then Auth will assume there is no user linked to auth info, and will return current auth info when get current user UserModel interface{} // Mount Auth into router with URLPrefix's value as prefix, default value is `/auth`. URLPrefix string // ViewPaths prepend views paths for auth ViewPaths []string // Auth is using [Render](https://github.com/qor/render) to render pages, you could configure it with your project's Render if you have advanced usage like [BindataFS](https://github.com/qor/bindatafs) Render *render.Render // Auth is using [Mailer](https://github.com/qor/mailer) to send email, by default, it will print email into console, you need to configure it to send real one Mailer *mailer.Mailer // UserStorer is an interface that defined how to get/save user, Auth provides a default one based on AuthIdentityModel, UserModel's definition UserStorer UserStorerInterface // SessionStorer is an interface that defined how to encode/validate/save/destroy session data and flash messages between requests, Auth provides a default method do the job, to use the default value, don't forgot to mount SessionManager's middleware into your router to save session data correctly. refer [session](https://github.com/qor/session) for more details SessionStorer SessionStorerInterface // Redirector redirect user to a new page after registered, logged, confirmed... Redirector RedirectorInterface // LoginHandler defined behaviour when request `{Auth Prefix}/login`, default behaviour defined in http://godoc.org/github.com/qor/auth#pkg-variables LoginHandler func(*Context, func(*Context) (*claims.Claims, error)) // RegisterHandler defined behaviour when request `{Auth Prefix}/register`, default behaviour defined in http://godoc.org/github.com/qor/auth#pkg-variables RegisterHandler func(*Context, func(*Context) (*claims.Claims, error)) // LogoutHandler defined behaviour when request `{Auth Prefix}/logout`, default behaviour defined in http://godoc.org/github.com/qor/auth#pkg-variables LogoutHandler func(*Context) }
Config auth config
type Context ¶
type Context struct { *Auth Claims *claims.Claims Provider Provider Request *http.Request Writer http.ResponseWriter }
Context context
type Provider ¶
type Provider interface { GetName() string ConfigAuth(*Auth) Login(*Context) Logout(*Context) Register(*Context) Callback(*Context) ServeHTTP(*Context) }
Provider define Provider interface
type Redirector ¶
type Redirector struct {
*redirect_back.RedirectBack
}
Redirector default redirector
func (Redirector) Redirect ¶
func (redirector Redirector) Redirect(w http.ResponseWriter, req *http.Request, action string)
Redirect redirect back after action
type RedirectorInterface ¶
type RedirectorInterface interface { // Redirect redirect after action Redirect(w http.ResponseWriter, req *http.Request, action string) }
RedirectorInterface redirector interface
type Schema ¶
type Schema struct { Provider string UID string // for password login EncryptedPassword string Name string Email string FirstName string LastName string Location string Image string Phone string URL string RawInfo interface{} }
Schema auth schema
type SessionStorer ¶
type SessionStorer struct { SessionName string SigningMethod jwt.SigningMethod SignedString string SessionManager session.ManagerInterface }
SessionStorer default session storer
func (*SessionStorer) Delete ¶
func (sessionStorer *SessionStorer) Delete(w http.ResponseWriter, req *http.Request) error
Delete delete claims from session manager
func (*SessionStorer) Flash ¶
func (sessionStorer *SessionStorer) Flash(w http.ResponseWriter, req *http.Request, message session.Message) error
Flash add flash message to session data
func (*SessionStorer) Flashes ¶
func (sessionStorer *SessionStorer) Flashes(w http.ResponseWriter, req *http.Request) []session.Message
Flashes returns a slice of flash messages from session data
func (*SessionStorer) SignedToken ¶
func (sessionStorer *SessionStorer) SignedToken(claims *claims.Claims) string
SignedToken generate signed token with Claims
func (*SessionStorer) Update ¶
func (sessionStorer *SessionStorer) Update(w http.ResponseWriter, req *http.Request, claims *claims.Claims) error
Update update claims with session manager
func (*SessionStorer) ValidateClaims ¶
func (sessionStorer *SessionStorer) ValidateClaims(tokenString string) (*claims.Claims, error)
ValidateClaims validate auth token
type SessionStorerInterface ¶
type SessionStorerInterface interface { // Get get claims from request Get(req *http.Request) (*claims.Claims, error) // Update update claims with session manager Update(w http.ResponseWriter, req *http.Request, claims *claims.Claims) error // Delete delete session Delete(w http.ResponseWriter, req *http.Request) error // Flash add flash message to session data Flash(w http.ResponseWriter, req *http.Request, message session.Message) error // Flashes returns a slice of flash messages from session data Flashes(w http.ResponseWriter, req *http.Request) []session.Message // SignedToken generate signed token with Claims SignedToken(claims *claims.Claims) string // ValidateClaims validate auth token ValidateClaims(tokenString string) (*claims.Claims, error) }
SessionStorerInterface session storer interface for Auth
type UserStorer ¶
type UserStorer struct { }
UserStorer default user storer