Authorization
Introduction
In addition to providing authentication services out of the box, Totoval also provides a simple way to authorize user actions against a given resource.
Think of policies like routes and controllers, Policies provide a simple interface which defined the resource that could or not be attached by user using which action. Such as a post should only be edited by its’ creator.
Creating Polices
Polices are structs that organize authorization logic around a particular model or resource. For example, if your application is a blog, you may have a Post model and a corresponding PostPolicy to authorize user actions such as creating or updating posts.
Polices should implement the interface Policier, which is defined at github.com/totoval/framework/policy/policy.go.
Here’s an example of PostPolicy:
package policies
import (
	"strconv"
	"github.com/totoval/framework/helpers/m"
	"totoval/app/models"
	"github.com/totoval/framework/model"
)
type postPolicy struct {
	post *models.Post
}
func NewPostPolicy(post *models.Post) *postPolicy {
	return &postPolicy{post: post}
}
func (pp *postPolicy) Before(IUser model.IUser, routeParamMap map[key]value) *bool {
	return nil
}
func (pp *postPolicy) Create(IUser model.IUser, routeParamMap map[string]string) bool { return true }
func (pp *postPolicy) Update(IUser model.IUser, routeParamMap map[string]string) bool      {
	// get current user
	currentUser := IUser.Value().(*models.User)
	// if use Authorize func, routeParamMap is nil
	if routeParamMap == nil {
		return true
	}
	// get current post
	postIdStr, ok := routeParamMap["postId"]
	
	...
	... // convert postIdStr and get currentPost from db
	...
	
	// user only can edit his own post
	if *currentUser.Id == *currentPost.UserId {
		return true
	}
	return false
}
func (pp *postPolicy) Delete(IUser model.IUser, routeParamMap map[string]string) bool      { return true }
func (pp *postPolicy) ForceDelete(IUser model.IUser, routeParamMap map[string]string) bool { return true }
func (pp *postPolicy) View(IUser model.IUser, routeParamMap map[string]string) bool { return true }
func (pp *postPolicy) Restore(IUser model.IUser, routeParamMap map[string]string) bool { return true }- Beforefunc will be called at the first- If Beforereturn nil, then it will call the Action you defined at routerCanor controllerAuthorizefunc.
- If Beforereturn a bool pointer, then it will immediately return the bool you returned as the Authorizing result. > Typically,Beforefunc usually used under the Admin circumstances.
 
- If 
- Other funcs like Create,Update, etc. are matched with the Action you defined at routerCanor controllerAuthorizefunc, the result of Authorization will be the bool you returned at these funcs.
Authorizing Actions Using Policies
Authorizing Route
type PostGroup struct {
	PostController controllers.Post
}
func (pg *PostGroup) Group(group route.Grouper) {
    group.PUT("/post/:postId", pg.PostController.Edit).Can(policies.NewPostPolicy(nil), policy.ActionUpdate)
}Authorize in Controller
func (p *Post) Edit(c *gin.Context) {
    ...
    ...
    // get current post
    postIdStr, ok := c.Param("postId")
    
    ...
    ... // convert postIdStr and get currentPost from db
    ...
    
    // Do Authorize
    permit, user := p.Authorize(c, policies.NewPostPolicy(¤tPost), policy.ActionView)
    if !permit{
        c.JSON(http.StatusForbidden, gin.H{"error": policy.UserNotPermitError{}.Error()})
        return
    }
    ...
    ...
}