feat: (rbac) middleware handle error / password bcrypt hash / user update password

This commit is contained in:
xushuhui 2022-04-20 10:22:53 +08:00
parent 7e9f39cb88
commit f6d4d9fda5
8 changed files with 124 additions and 52 deletions

View File

@ -3,12 +3,14 @@ package biz
import (
"errors"
"fmt"
"github.com/golang-jwt/jwt"
"golang.org/x/crypto/bcrypt"
"infini.sh/console/internal/dto"
"infini.sh/console/model/rbac"
"infini.sh/framework/core/event"
"infini.sh/framework/core/global"
"infini.sh/framework/core/orm"
"infini.sh/framework/core/util"
"src/github.com/golang-jwt/jwt"
"strings"
"time"
)
@ -26,11 +28,10 @@ type User struct {
const Secret = "console"
func authenticateUser(username string, password string) (user rbac.User, err error) {
q := orm.Query{Size: 1000}
q.Conds = orm.And(orm.Eq("username", username))
err, result := orm.Search(rbac.User{}, &q)
err, result := orm.GetBy("username", username, rbac.User{})
if err != nil {
err = ErrNotFound
return
}
if result.Total == 0 {
@ -38,10 +39,12 @@ func authenticateUser(username string, password string) (user rbac.User, err err
return
}
user = result.Result[0].(rbac.User)
if util.MD5digest(password) != user.Password {
err = errors.New("password error")
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
if err == bcrypt.ErrMismatchedHashAndPassword {
err = errors.New("password incorrect")
return
}
return
}
func authenticateAdmin(username string, password string) (user rbac.User, err error) {
@ -62,7 +65,7 @@ func authorize(user rbac.User) (m map[string]interface{}, err error) {
User: &User{
Username: user.Username,
UserId: user.ID,
Roles: []string{"admin"},
Roles: []string{"admin_user"},
},
RegisteredClaims: &jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
@ -76,7 +79,9 @@ func authorize(user rbac.User) (m map[string]interface{}, err error) {
m = util.MapStr{
"access_token": tokenString,
"username": user.Username,
"userid": user.ID,
"id": user.ID,
"expire_in": 86400,
"roles": []string{"admin_user"},
}
return
}
@ -115,7 +120,30 @@ func Login(username string, password string) (m map[string]interface{}, err erro
}, nil, nil))
return
}
func UpdatePassword(localUser *User, req dto.UpdatePassword) (err error) {
user := rbac.User{}
user.ID = localUser.UserId
_, err = orm.Get(&user)
if err != nil {
err = ErrNotFound
return
}
err = bcrypt.CompareHashAndPassword([]byte(req.OldPassword), []byte(user.Password))
if err == bcrypt.ErrMismatchedHashAndPassword {
err = errors.New("old password is not correct")
return
}
hash, err := bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost)
if err != nil {
return
}
user.Password = string(hash)
err = orm.Save(&user)
if err != nil {
return
}
return
}
func ValidateLogin(authorizationHeader string) (clams *UserClaims, err error) {
if authorizationHeader == "" {
@ -151,10 +179,7 @@ func ValidateLogin(authorizationHeader string) (clams *UserClaims, err error) {
func ValidatePermission(claims *UserClaims, permissions []string) (err error) {
reqUser := claims.User
if err != nil {
return
}
if reqUser.UserId == "" {
err = errors.New("user id is empty")
return

View File

@ -35,7 +35,7 @@ const InstanceProxy = "instance_proxy"
var Admin = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser, CreateRole, UpdateRole, DeleteRole, GetRole, SearchRole, ListPermission}
var AdminUser = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser}
var AdminRole = []string{CreateRole, UpdateRole, DeleteRole, GetRole, SearchRole, ListPermission}
var BuildRoles = []rbac.Role{
{
ORMObjectBase: orm.ORMObjectBase{

View File

@ -1,6 +1,9 @@
package biz
import "fmt"
import (
"fmt"
"infini.sh/console/internal/biz/enum"
)
var ClusterApis = make([]string, 0)
var EsApis = make(map[string][]string)
@ -38,33 +41,37 @@ type ConsolePermisson struct {
}
func (r ConsoleRole) ListPermission() interface{} {
list := []ConsolePermisson{
{
Id: "cluster_overview",
Name: "平台概览",
},
{
Id: "cluster_search",
Name: "平台搜索",
},
{
Id: "cluster_elasticsearch",
Name: "集群监控",
},
{
Id: "cluster_elasticsearch_refresh",
Name: "集群监控刷新",
},
{
Id: "cluster_activities",
Name: "集群动态",
},
{
Id: "cluster_activities_search",
Name: "集群动态搜索",
},
}
return list
//list := []ConsolePermisson{
// {
// Id: "cluster_overview",
// Name: "平台概览",
// },
// {
// Id: "cluster_search",
// Name: "平台搜索",
// },
// {
// Id: "cluster_elasticsearch",
// Name: "集群监控",
// },
// {
// Id: "cluster_elasticsearch_refresh",
// Name: "集群监控刷新",
// },
// {
// Id: "cluster_activities",
// Name: "集群动态",
// },
// {
// Id: "cluster_activities_search",
// Name: "集群动态搜索",
// },
//
//}
m := make(map[string]map[string][]string)
m["api"]["用户管理"] = enum.AdminUser
m["api"]["角色管理"] = enum.AdminRole
return m
}
func (r ElasticsearchRole) ListPermission() interface{} {
list := ElasticsearchPermisson{

View File

@ -5,13 +5,11 @@ import (
"infini.sh/console/internal/dto"
"infini.sh/console/model/rbac"
"infini.sh/framework/core/event"
log "src/github.com/cihub/seelog"
"infini.sh/framework/core/orm"
"infini.sh/framework/core/util"
log "src/github.com/cihub/seelog"
"strings"
"time"
"infini.sh/framework/core/orm"
)
func CreateRole(localUser *User, req dto.CreateRole) (id string, err error) {

View File

@ -2,6 +2,7 @@ package biz
import (
"fmt"
"golang.org/x/crypto/bcrypt"
"infini.sh/console/internal/dto"
"infini.sh/console/model/rbac"
"infini.sh/framework/core/event"
@ -73,10 +74,15 @@ func CreateUser(localUser *User, req dto.CreateUser) (id string, err error) {
Name: v.Name,
})
}
hash, err := bcrypt.GenerateFromPassword([]byte("123456"), bcrypt.DefaultCost)
if err != nil {
return
}
user := rbac.User{
Name: req.Name,
Username: req.Username,
Password: util.MD5digest(req.Password),
Password: string(hash),
Email: req.Email,
Phone: req.Phone,
Roles: roles,

View File

@ -4,3 +4,7 @@ type Login struct {
Username string `json:"username"`
Password string `json:"password"`
}
type UpdatePassword struct {
OldPassword string `json:"oldPassword"`
NewPassword string `json:"newPassword"`
}

View File

@ -12,7 +12,7 @@ func LoginRequired(h httprouter.Handle) httprouter.Handle {
claims, err := biz.ValidateLogin(r.Header.Get("Authorization"))
if err != nil {
w = handleError(w, err)
w = handleError(w, http.StatusUnauthorized, err)
return
}
r = r.WithContext(biz.NewUserContext(r.Context(), claims))
@ -24,21 +24,30 @@ func PermissionRequired(h httprouter.Handle, permissions ...string) httprouter.H
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
claims, err := biz.ValidateLogin(r.Header.Get("Authorization"))
if err != nil {
w = handleError(w, err)
w = handleError(w, http.StatusUnauthorized, err)
return
}
err = biz.ValidatePermission(claims, permissions)
if err != nil {
w = handleError(w, err)
w = handleError(w, http.StatusForbidden, err)
return
}
r = r.WithContext(biz.NewUserContext(r.Context(), claims))
h(w, r, ps)
}
}
func handleError(w http.ResponseWriter, err error) http.ResponseWriter {
func handleError(w http.ResponseWriter, statusCode int, err error) http.ResponseWriter {
w.Header().Set("Content-type", util.ContentTypeJson)
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(`{"error":"` + err.Error() + `"}`))
w.WriteHeader(statusCode)
json := util.ToJson(util.MapStr{
"error": util.MapStr{
"status": statusCode,
"reason": err.Error(),
},
}, true)
w.Write([]byte(json))
return w
}

View File

@ -22,6 +22,7 @@ func init() {
api.HandleAPIMethod(api.DELETE, "/account/logout", account.Logout)
api.HandleAPIMethod(api.GET, "/account/profile", m.LoginRequired(account.Profile))
api.HandleAPIMethod(api.PUT, "/account/password", m.LoginRequired(account.UpdatePassword))
}
const userInSession = "user_in_session"
@ -101,3 +102,25 @@ func (h Account) Profile(w http.ResponseWriter, r *http.Request, ps httprouter.P
h.WriteJSON(w, reqUser, 200)
return
}
func (h Account) UpdatePassword(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
reqUser, err := biz.FromUserContext(r.Context())
if err != nil {
h.Error(w, err)
return
}
var req dto.UpdatePassword
err = h.DecodeJSON(r, &req)
if err != nil {
h.Error(w, err)
return
}
err = biz.UpdatePassword(reqUser, req)
if err != nil {
h.Error(w, err)
return
}
h.WriteOKJSON(w, util.MapStr{
"status": "ok",
})
}