github.com/kotovmak/go-admin@v1.1.1/modules/auth/auth.go (about)

     1  // Copyright 2019 GoAdmin Core Team. All rights reserved.
     2  // Use of this source code is governed by a Apache-2.0 style
     3  // license that can be found in the LICENSE file.
     4  
     5  package auth
     6  
     7  import (
     8  	"sync"
     9  
    10  	"github.com/kotovmak/go-admin/modules/db/dialect"
    11  	"github.com/kotovmak/go-admin/modules/logger"
    12  
    13  	"github.com/kotovmak/go-admin/context"
    14  	"github.com/kotovmak/go-admin/modules/db"
    15  	"github.com/kotovmak/go-admin/modules/service"
    16  	"github.com/kotovmak/go-admin/plugins/admin/models"
    17  	"github.com/kotovmak/go-admin/plugins/admin/modules"
    18  	"golang.org/x/crypto/bcrypt"
    19  )
    20  
    21  // Auth get the user model from Context.
    22  func Auth(ctx *context.Context) models.UserModel {
    23  	return ctx.User().(models.UserModel)
    24  }
    25  
    26  // Check check the password and username and return the user model.
    27  func Check(password string, username string, conn db.Connection) (user models.UserModel, ok bool) {
    28  
    29  	user = models.User().SetConn(conn).FindByUserName(username)
    30  
    31  	if user.IsEmpty() {
    32  		ok = false
    33  	} else {
    34  		if comparePassword(password, user.Password) {
    35  			ok = true
    36  			user = user.WithRoles().WithPermissions().WithMenus()
    37  			user.UpdatePwd(EncodePassword([]byte(password)))
    38  		} else {
    39  			ok = false
    40  		}
    41  	}
    42  	return
    43  }
    44  
    45  func comparePassword(comPwd, pwdHash string) bool {
    46  	err := bcrypt.CompareHashAndPassword([]byte(pwdHash), []byte(comPwd))
    47  	return err == nil
    48  }
    49  
    50  // EncodePassword encode the password.
    51  func EncodePassword(pwd []byte) string {
    52  	hash, err := bcrypt.GenerateFromPassword(pwd, bcrypt.DefaultCost)
    53  	if err != nil {
    54  		return ""
    55  	}
    56  	return string(hash)
    57  }
    58  
    59  // SetCookie set the cookie.
    60  func SetCookie(ctx *context.Context, user models.UserModel, conn db.Connection) error {
    61  	ses, err := InitSession(ctx, conn)
    62  
    63  	if err != nil {
    64  		return err
    65  	}
    66  
    67  	return ses.Add("user_id", user.Id)
    68  }
    69  
    70  // DelCookie delete the cookie from Context.
    71  func DelCookie(ctx *context.Context, conn db.Connection) error {
    72  	ses, err := InitSession(ctx, conn)
    73  
    74  	if err != nil {
    75  		return err
    76  	}
    77  
    78  	return ses.Clear()
    79  }
    80  
    81  type TokenService struct {
    82  	tokens CSRFToken
    83  	lock   sync.Mutex
    84  	conn   db.Connection
    85  }
    86  
    87  func (s *TokenService) Name() string {
    88  	return TokenServiceKey
    89  }
    90  
    91  func InitCSRFTokenSrv(conn db.Connection) (string, service.Service) {
    92  	list, err := db.WithDriver(conn).Table("goadmin_session").
    93  		Where("values", "=", "__csrf_token__").
    94  		All()
    95  	if db.CheckError(err, db.QUERY) {
    96  		logger.Error("csrf token query from database error: ", err)
    97  	}
    98  	tokens := make(CSRFToken, len(list))
    99  	for i := 0; i < len(list); i++ {
   100  		tokens[i] = list[i]["sid"].(string)
   101  	}
   102  	return TokenServiceKey, &TokenService{
   103  		tokens: tokens,
   104  		conn:   conn,
   105  	}
   106  }
   107  
   108  const (
   109  	TokenServiceKey = "token_csrf_helper"
   110  	ServiceKey      = "auth"
   111  )
   112  
   113  func GetTokenService(s interface{}) *TokenService {
   114  	if srv, ok := s.(*TokenService); ok {
   115  		return srv
   116  	}
   117  	panic("wrong service")
   118  }
   119  
   120  // AddToken add the token to the CSRFToken.
   121  func (s *TokenService) AddToken() string {
   122  	s.lock.Lock()
   123  	defer s.lock.Unlock()
   124  	tokenStr := modules.Uuid()
   125  	s.tokens = append(s.tokens, tokenStr)
   126  	_, err := db.WithDriver(s.conn).Table("goadmin_session").Insert(dialect.H{
   127  		"sid":    tokenStr,
   128  		"values": "__csrf_token__",
   129  	})
   130  	if db.CheckError(err, db.INSERT) {
   131  		logger.Error("csrf token insert into database error: ", err)
   132  	}
   133  	return tokenStr
   134  }
   135  
   136  // CheckToken check the given token with tokens in the CSRFToken, if exist
   137  // return true.
   138  func (s *TokenService) CheckToken(toCheckToken string) bool {
   139  	for i := 0; i < len(s.tokens); i++ {
   140  		if (s.tokens)[i] == toCheckToken {
   141  			s.tokens = append((s.tokens)[:i], (s.tokens)[i+1:]...)
   142  			err := db.WithDriver(s.conn).Table("goadmin_session").
   143  				Where("sid", "=", toCheckToken).
   144  				Where("values", "=", "__csrf_token__").
   145  				Delete()
   146  			if db.CheckError(err, db.DELETE) {
   147  				logger.Error("csrf token delete from database error: ", err)
   148  			}
   149  			return true
   150  		}
   151  	}
   152  	return false
   153  }
   154  
   155  // CSRFToken is type of a csrf token list.
   156  type CSRFToken []string
   157  
   158  type Processor func(ctx *context.Context) (model models.UserModel, exist bool, msg string)
   159  
   160  type Service struct {
   161  	P Processor
   162  }
   163  
   164  func (s *Service) Name() string {
   165  	return "auth"
   166  }
   167  
   168  func GetService(s interface{}) *Service {
   169  	if srv, ok := s.(*Service); ok {
   170  		return srv
   171  	}
   172  	panic("wrong service")
   173  }
   174  
   175  func NewService(processor Processor) *Service {
   176  	return &Service{
   177  		P: processor,
   178  	}
   179  }