mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 02:31:04 +01:00
add authenticated-controller example - proof of concept
Former-commit-id: 7a15da2bd966f2a699337cd494af8b5d1877b11d
This commit is contained in:
parent
47075a82e9
commit
ffc493a0b9
|
@ -170,6 +170,7 @@
|
||||||
* [Singleton](mvc/singleton)
|
* [Singleton](mvc/singleton)
|
||||||
* [Regexp](mvc/regexp/main.go)
|
* [Regexp](mvc/regexp/main.go)
|
||||||
* [Session Controller](mvc/session-controller/main.go)
|
* [Session Controller](mvc/session-controller/main.go)
|
||||||
|
* [Authenticated Controller](mvc/authenticated-controller/main.go)
|
||||||
* [Websocket Controller](mvc/websocket)
|
* [Websocket Controller](mvc/websocket)
|
||||||
* [Register Middleware](mvc/middleware)
|
* [Register Middleware](mvc/middleware)
|
||||||
* Object-Relational Mapping
|
* Object-Relational Mapping
|
||||||
|
|
104
_examples/mvc/authenticated-controller/main.go
Normal file
104
_examples/mvc/authenticated-controller/main.go
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
// Package main shows how to use a dependency to check if a user is logged in
|
||||||
|
// using a special custom Go type `Authenticated`, which when,
|
||||||
|
// present on a controller's method or a field then
|
||||||
|
// it limits the visibility to "authenticated" users only.
|
||||||
|
//
|
||||||
|
// The same result could be done through a middleware as well, however using a static type
|
||||||
|
// any person reads your code can see that an "X" controller or method
|
||||||
|
// should only be used by "authenticated" users.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kataras/iris/v12"
|
||||||
|
"github.com/kataras/iris/v12/mvc"
|
||||||
|
"github.com/kataras/iris/v12/sessions"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := iris.New()
|
||||||
|
app.Logger().SetLevel("debug")
|
||||||
|
|
||||||
|
sess := sessions.New(sessions.Config{
|
||||||
|
Cookie: "myapp_session_id",
|
||||||
|
AllowReclaim: true,
|
||||||
|
})
|
||||||
|
app.Use(sess.Handler())
|
||||||
|
|
||||||
|
userRouter := app.Party("/user")
|
||||||
|
{
|
||||||
|
// Initialize a new MVC application on top of the "userRouter".
|
||||||
|
userApp := mvc.New(userRouter)
|
||||||
|
// Register Dependencies.
|
||||||
|
userApp.Register(authDependency)
|
||||||
|
|
||||||
|
// Register Controllers.
|
||||||
|
userApp.Handle(new(MeController))
|
||||||
|
userApp.Handle(new(UserController))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open a client, e.g. Postman and visit the below endpoints.
|
||||||
|
// GET: http://localhost:8080/user
|
||||||
|
// POST: http://localhost:8080/user/login
|
||||||
|
// GET: http://localhost:8080/user
|
||||||
|
// GET: http://localhost:8080/user/me
|
||||||
|
// POST: http://localhost:8080/user/logout
|
||||||
|
app.Listen(":8080")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authenticated is a custom type used as "annotation" for resources that requires authentication,
|
||||||
|
// its value should be the logged user ID.
|
||||||
|
type Authenticated uint64
|
||||||
|
|
||||||
|
func authDependency(ctx iris.Context, session *sessions.Session) Authenticated {
|
||||||
|
userID := session.GetUint64Default("user_id", 0)
|
||||||
|
if userID == 0 {
|
||||||
|
// If execution was stopped
|
||||||
|
// any controller's method will not be executed at all.
|
||||||
|
ctx.StopWithStatus(iris.StatusUnauthorized)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return Authenticated(userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserController serves the "public" User API.
|
||||||
|
type UserController struct {
|
||||||
|
Session *sessions.Session
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostLogin serves
|
||||||
|
// POST: /user/login
|
||||||
|
func (c *UserController) PostLogin() mvc.Response {
|
||||||
|
c.Session.Set("user_id", 1)
|
||||||
|
|
||||||
|
// Redirect (you can still use the Context.Redirect if you want so).
|
||||||
|
return mvc.Response{
|
||||||
|
Path: "/user",
|
||||||
|
Code: iris.StatusFound,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostLogout serves
|
||||||
|
// POST: /user/logout
|
||||||
|
func (c *UserController) PostLogout(ctx iris.Context) {
|
||||||
|
c.Session.Man.Destroy(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMe showcases that the same type can be used inside controller's method too,
|
||||||
|
// a second controller like `MeController` is not required.
|
||||||
|
// GET: user/me
|
||||||
|
func (c *UserController) GetMe(_ Authenticated) string {
|
||||||
|
return `UserController.GetMe: The Authenticated type
|
||||||
|
can be used to secure a controller's method too.`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MeController provides the logged user's available actions.
|
||||||
|
type MeController struct {
|
||||||
|
CurrentUserID Authenticated
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns a message for the shake of the example.
|
||||||
|
// GET: /user
|
||||||
|
func (c *MeController) Get() string {
|
||||||
|
return "This will be executed only when the user is logged in"
|
||||||
|
}
|
|
@ -61,7 +61,7 @@ func main() {
|
||||||
}
|
}
|
||||||
db.AutoMigrate(&User{}) // create table: // AutoMigrate run auto migration for given models, will only add missing fields, won't delete/change current data
|
db.AutoMigrate(&User{}) // create table: // AutoMigrate run auto migration for given models, will only add missing fields, won't delete/change current data
|
||||||
|
|
||||||
app.Post("/post_user", func(context iris.Context) {
|
app.Post("/post_user", func(ctx iris.Context) {
|
||||||
var user User
|
var user User
|
||||||
user = User{
|
user = User{
|
||||||
Username: "gorm",
|
Username: "gorm",
|
||||||
|
@ -71,41 +71,41 @@ func main() {
|
||||||
}
|
}
|
||||||
if err := db.FirstOrCreate(&user); err == nil {
|
if err := db.FirstOrCreate(&user); err == nil {
|
||||||
app.Logger().Fatalf("created one record failed: %s", err.Error)
|
app.Logger().Fatalf("created one record failed: %s", err.Error)
|
||||||
context.JSON(iris.Map{
|
ctx.JSON(iris.Map{
|
||||||
"code": http.StatusBadRequest,
|
"code": http.StatusBadRequest,
|
||||||
"error": err.Error,
|
"error": err.Error,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
context.JSON(
|
ctx.JSON(
|
||||||
iris.Map{
|
iris.Map{
|
||||||
"code": http.StatusOK,
|
"code": http.StatusOK,
|
||||||
"data": user.Serializer(),
|
"data": user.Serializer(),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
app.Get("/get_user/{id:uint}", func(context iris.Context) {
|
app.Get("/get_user/{id:uint}", func(ctx iris.Context) {
|
||||||
var user User
|
var user User
|
||||||
id, _ := context.Params().GetUint("id")
|
id, _ := ctx.Params().GetUint("id")
|
||||||
app.Logger().Println(id)
|
app.Logger().Println(id)
|
||||||
if err := db.Where("id = ?", int(id)).First(&user).Error; err != nil {
|
if err := db.Where("id = ?", int(id)).First(&user).Error; err != nil {
|
||||||
app.Logger().Fatalf("find one record failed: %t", err == nil)
|
app.Logger().Fatalf("find one record failed: %t", err == nil)
|
||||||
context.JSON(iris.Map{
|
ctx.JSON(iris.Map{
|
||||||
"code": http.StatusBadRequest,
|
"code": http.StatusBadRequest,
|
||||||
"error": err.Error,
|
"error": err.Error,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
context.JSON(iris.Map{
|
ctx.JSON(iris.Map{
|
||||||
"code": http.StatusOK,
|
"code": http.StatusOK,
|
||||||
"data": user.Serializer(),
|
"data": user.Serializer(),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
app.Delete("/delete_user/{id:uint}", func(context iris.Context) {
|
app.Delete("/delete_user/{id:uint}", func(ctx iris.Context) {
|
||||||
id, _ := context.Params().GetUint("id")
|
id, _ := ctx.Params().GetUint("id")
|
||||||
if id == 0 {
|
if id == 0 {
|
||||||
context.JSON(iris.Map{
|
ctx.JSON(iris.Map{
|
||||||
"code": http.StatusOK,
|
"code": http.StatusOK,
|
||||||
"detail": "query param id should not be nil",
|
"detail": "query param id should not be nil",
|
||||||
})
|
})
|
||||||
|
@ -114,23 +114,23 @@ func main() {
|
||||||
var user User
|
var user User
|
||||||
if err := db.Where("id = ?", id).First(&user).Error; err != nil {
|
if err := db.Where("id = ?", id).First(&user).Error; err != nil {
|
||||||
app.Logger().Fatalf("record not found")
|
app.Logger().Fatalf("record not found")
|
||||||
context.JSON(iris.Map{
|
ctx.JSON(iris.Map{
|
||||||
"code": http.StatusOK,
|
"code": http.StatusOK,
|
||||||
"detail": err.Error,
|
"detail": err.Error,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
db.Delete(&user)
|
db.Delete(&user)
|
||||||
context.JSON(iris.Map{
|
ctx.JSON(iris.Map{
|
||||||
"code": http.StatusOK,
|
"code": http.StatusOK,
|
||||||
"data": user.Serializer(),
|
"data": user.Serializer(),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
app.Patch("/patch_user/{id:uint}", func(context iris.Context) {
|
app.Patch("/patch_user/{id:uint}", func(ctx iris.Context) {
|
||||||
id, _ := context.Params().GetUint("id")
|
id, _ := ctx.Params().GetUint("id")
|
||||||
if id == 0 {
|
if id == 0 {
|
||||||
context.JSON(iris.Map{
|
ctx.JSON(iris.Map{
|
||||||
"code": http.StatusOK,
|
"code": http.StatusOK,
|
||||||
"detail": "query param id should not be nil",
|
"detail": "query param id should not be nil",
|
||||||
})
|
})
|
||||||
|
@ -140,7 +140,7 @@ func main() {
|
||||||
tx := db.Begin()
|
tx := db.Begin()
|
||||||
if err := tx.Where("id = ?", id).First(&user).Error; err != nil {
|
if err := tx.Where("id = ?", id).First(&user).Error; err != nil {
|
||||||
app.Logger().Fatalf("record not found")
|
app.Logger().Fatalf("record not found")
|
||||||
context.JSON(iris.Map{
|
ctx.JSON(iris.Map{
|
||||||
"code": http.StatusOK,
|
"code": http.StatusOK,
|
||||||
"detail": err.Error,
|
"detail": err.Error,
|
||||||
})
|
})
|
||||||
|
@ -148,19 +148,19 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var body patchParam
|
var body patchParam
|
||||||
context.ReadJSON(&body)
|
ctx.ReadJSON(&body)
|
||||||
app.Logger().Println(body)
|
app.Logger().Println(body)
|
||||||
if err := tx.Model(&user).Updates(map[string]interface{}{"username": body.Data.UserName, "password": body.Data.Password}).Error; err != nil {
|
if err := tx.Model(&user).Updates(map[string]interface{}{"username": body.Data.UserName, "password": body.Data.Password}).Error; err != nil {
|
||||||
app.Logger().Fatalf("update record failed")
|
app.Logger().Fatalf("update record failed")
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
context.JSON(iris.Map{
|
ctx.JSON(iris.Map{
|
||||||
"code": http.StatusBadRequest,
|
"code": http.StatusBadRequest,
|
||||||
"error": err.Error,
|
"error": err.Error,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tx.Commit()
|
tx.Commit()
|
||||||
context.JSON(iris.Map{
|
ctx.JSON(iris.Map{
|
||||||
"code": http.StatusOK,
|
"code": http.StatusOK,
|
||||||
"data": user.Serializer(),
|
"data": user.Serializer(),
|
||||||
})
|
})
|
||||||
|
|
|
@ -14,9 +14,9 @@ func TestRouteRegisterRuleExample(t *testing.T) {
|
||||||
for _, method := range router.AllMethods {
|
for _, method := range router.AllMethods {
|
||||||
tt := e.Request(method, "/").Expect().Status(httptest.StatusOK).Body()
|
tt := e.Request(method, "/").Expect().Status(httptest.StatusOK).Body()
|
||||||
if method == "GET" {
|
if method == "GET" {
|
||||||
tt.Equal("From GET: github.com/kataras/iris/v12/_examples/routing/route-register-rule.getHandler")
|
tt.Equal("From GET: iris/_examples/routing/route-register-rule.getHandler")
|
||||||
} else {
|
} else {
|
||||||
tt.Equal("From " + method + ": github.com/kataras/iris/v12/_examples/routing/route-register-rule.anyHandler")
|
tt.Equal("From " + method + ": iris/_examples/routing/route-register-rule.anyHandler")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
// +build go1.9
|
|
||||||
|
|
||||||
package iris
|
package iris
|
||||||
|
|
||||||
import (
|
import (
|
|
@ -1,5 +1,3 @@
|
||||||
// +build go1.9
|
|
||||||
|
|
||||||
package httptest
|
package httptest
|
||||||
|
|
||||||
import "github.com/gavv/httpexpect"
|
import "github.com/gavv/httpexpect"
|
|
@ -1,6 +1,7 @@
|
||||||
package sessions
|
package sessions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -225,6 +226,7 @@ func newErrEntryNotFound(key string, kind reflect.Kind, value interface{}) *ErrE
|
||||||
func (s *Session) GetInt(key string) (int, error) {
|
func (s *Session) GetInt(key string) (int, error) {
|
||||||
v := s.Get(key)
|
v := s.Get(key)
|
||||||
|
|
||||||
|
if v != nil {
|
||||||
if vint, ok := v.(int); ok {
|
if vint, ok := v.(int); ok {
|
||||||
return vint, nil
|
return vint, nil
|
||||||
}
|
}
|
||||||
|
@ -240,6 +242,7 @@ func (s *Session) GetInt(key string) (int, error) {
|
||||||
if vstring, sok := v.(string); sok {
|
if vstring, sok := v.(string); sok {
|
||||||
return strconv.Atoi(vstring)
|
return strconv.Atoi(vstring)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return -1, newErrEntryNotFound(key, reflect.Int, v)
|
return -1, newErrEntryNotFound(key, reflect.Int, v)
|
||||||
}
|
}
|
||||||
|
@ -277,7 +280,7 @@ func (s *Session) Decrement(key string, n int) (newValue int) {
|
||||||
// if key doesn't exist then it returns -1 and a non-nil error.
|
// if key doesn't exist then it returns -1 and a non-nil error.
|
||||||
func (s *Session) GetInt64(key string) (int64, error) {
|
func (s *Session) GetInt64(key string) (int64, error) {
|
||||||
v := s.Get(key)
|
v := s.Get(key)
|
||||||
|
if v != nil {
|
||||||
if vint64, ok := v.(int64); ok {
|
if vint64, ok := v.(int64); ok {
|
||||||
return vint64, nil
|
return vint64, nil
|
||||||
}
|
}
|
||||||
|
@ -293,6 +296,7 @@ func (s *Session) GetInt64(key string) (int64, error) {
|
||||||
if vstring, sok := v.(string); sok {
|
if vstring, sok := v.(string); sok {
|
||||||
return strconv.ParseInt(vstring, 10, 64)
|
return strconv.ParseInt(vstring, 10, 64)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return -1, newErrEntryNotFound(key, reflect.Int64, v)
|
return -1, newErrEntryNotFound(key, reflect.Int64, v)
|
||||||
}
|
}
|
||||||
|
@ -307,6 +311,49 @@ func (s *Session) GetInt64Default(key string, defaultValue int64) int64 {
|
||||||
return defaultValue
|
return defaultValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUint64 same as `Get` but returns as uint64,
|
||||||
|
// if key doesn't exist then it returns 0 and a non-nil error.
|
||||||
|
func (s *Session) GetUint64(key string) (uint64, error) {
|
||||||
|
v := s.Get(key)
|
||||||
|
if v != nil {
|
||||||
|
switch vv := v.(type) {
|
||||||
|
case string:
|
||||||
|
val, err := strconv.ParseUint(vv, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if val > math.MaxUint64 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return uint64(val), nil
|
||||||
|
case uint8:
|
||||||
|
return uint64(vv), nil
|
||||||
|
case uint16:
|
||||||
|
return uint64(vv), nil
|
||||||
|
case uint32:
|
||||||
|
return uint64(vv), nil
|
||||||
|
case uint64:
|
||||||
|
return vv, nil
|
||||||
|
case int64:
|
||||||
|
return uint64(vv), nil
|
||||||
|
case int:
|
||||||
|
return uint64(vv), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, newErrEntryNotFound(key, reflect.Uint64, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUint64Default same as `Get` but returns as uint64,
|
||||||
|
// if key doesn't exist it returns the "defaultValue".
|
||||||
|
func (s *Session) GetUint64Default(key string, defaultValue uint64) uint64 {
|
||||||
|
if v, err := s.GetUint64(key); err == nil {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
// GetFloat32 same as `Get` but returns its float32 representation,
|
// GetFloat32 same as `Get` but returns its float32 representation,
|
||||||
// if key doesn't exist then it returns -1 and a non-nil error.
|
// if key doesn't exist then it returns -1 and a non-nil error.
|
||||||
func (s *Session) GetFloat32(key string) (float32, error) {
|
func (s *Session) GetFloat32(key string) (float32, error) {
|
||||||
|
|
|
@ -7,6 +7,10 @@ import (
|
||||||
"github.com/kataras/iris/v12/context"
|
"github.com/kataras/iris/v12/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
context.SetHandlerName("iris/sessions.*Handler", "iris.session")
|
||||||
|
}
|
||||||
|
|
||||||
// A Sessions manager should be responsible to Start a sesion, based
|
// A Sessions manager should be responsible to Start a sesion, based
|
||||||
// on a Context, which should return
|
// on a Context, which should return
|
||||||
// a compatible Session interface, type. If the external session manager
|
// a compatible Session interface, type. If the external session manager
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
// +build go1.9
|
|
||||||
|
|
||||||
package websocket
|
package websocket
|
||||||
|
|
||||||
import (
|
import (
|
Loading…
Reference in New Issue
Block a user