feat: (rbac) middleware handle error / password bcrypt hash / user update password
This commit is contained in:
parent
7e9f39cb88
commit
f6d4d9fda5
|
@ -3,12 +3,14 @@ package biz
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/golang-jwt/jwt"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
"infini.sh/console/internal/dto"
|
||||||
"infini.sh/console/model/rbac"
|
"infini.sh/console/model/rbac"
|
||||||
"infini.sh/framework/core/event"
|
"infini.sh/framework/core/event"
|
||||||
"infini.sh/framework/core/global"
|
"infini.sh/framework/core/global"
|
||||||
"infini.sh/framework/core/orm"
|
"infini.sh/framework/core/orm"
|
||||||
"infini.sh/framework/core/util"
|
"infini.sh/framework/core/util"
|
||||||
"src/github.com/golang-jwt/jwt"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -26,11 +28,10 @@ type User struct {
|
||||||
const Secret = "console"
|
const Secret = "console"
|
||||||
|
|
||||||
func authenticateUser(username string, password string) (user rbac.User, err error) {
|
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 {
|
if err != nil {
|
||||||
|
err = ErrNotFound
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if result.Total == 0 {
|
if result.Total == 0 {
|
||||||
|
@ -38,10 +39,12 @@ func authenticateUser(username string, password string) (user rbac.User, err err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user = result.Result[0].(rbac.User)
|
user = result.Result[0].(rbac.User)
|
||||||
if util.MD5digest(password) != user.Password {
|
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
|
||||||
err = errors.New("password error")
|
if err == bcrypt.ErrMismatchedHashAndPassword {
|
||||||
|
err = errors.New("password incorrect")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func authenticateAdmin(username string, password string) (user rbac.User, err error) {
|
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{
|
User: &User{
|
||||||
Username: user.Username,
|
Username: user.Username,
|
||||||
UserId: user.ID,
|
UserId: user.ID,
|
||||||
Roles: []string{"admin"},
|
Roles: []string{"admin_user"},
|
||||||
},
|
},
|
||||||
RegisteredClaims: &jwt.RegisteredClaims{
|
RegisteredClaims: &jwt.RegisteredClaims{
|
||||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
|
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{
|
m = util.MapStr{
|
||||||
"access_token": tokenString,
|
"access_token": tokenString,
|
||||||
"username": user.Username,
|
"username": user.Username,
|
||||||
"userid": user.ID,
|
"id": user.ID,
|
||||||
|
"expire_in": 86400,
|
||||||
|
"roles": []string{"admin_user"},
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -115,7 +120,30 @@ func Login(username string, password string) (m map[string]interface{}, err erro
|
||||||
}, nil, nil))
|
}, nil, nil))
|
||||||
return
|
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) {
|
func ValidateLogin(authorizationHeader string) (clams *UserClaims, err error) {
|
||||||
|
|
||||||
if authorizationHeader == "" {
|
if authorizationHeader == "" {
|
||||||
|
@ -151,10 +179,7 @@ func ValidateLogin(authorizationHeader string) (clams *UserClaims, err error) {
|
||||||
func ValidatePermission(claims *UserClaims, permissions []string) (err error) {
|
func ValidatePermission(claims *UserClaims, permissions []string) (err error) {
|
||||||
|
|
||||||
reqUser := claims.User
|
reqUser := claims.User
|
||||||
if err != nil {
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if reqUser.UserId == "" {
|
if reqUser.UserId == "" {
|
||||||
err = errors.New("user id is empty")
|
err = errors.New("user id is empty")
|
||||||
return
|
return
|
||||||
|
|
|
@ -35,7 +35,7 @@ const InstanceProxy = "instance_proxy"
|
||||||
|
|
||||||
var Admin = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser, CreateRole, UpdateRole, DeleteRole, GetRole, SearchRole, ListPermission}
|
var Admin = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser, CreateRole, UpdateRole, DeleteRole, GetRole, SearchRole, ListPermission}
|
||||||
var AdminUser = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser}
|
var AdminUser = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser}
|
||||||
|
var AdminRole = []string{CreateRole, UpdateRole, DeleteRole, GetRole, SearchRole, ListPermission}
|
||||||
var BuildRoles = []rbac.Role{
|
var BuildRoles = []rbac.Role{
|
||||||
{
|
{
|
||||||
ORMObjectBase: orm.ORMObjectBase{
|
ORMObjectBase: orm.ORMObjectBase{
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package biz
|
package biz
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"infini.sh/console/internal/biz/enum"
|
||||||
|
)
|
||||||
|
|
||||||
var ClusterApis = make([]string, 0)
|
var ClusterApis = make([]string, 0)
|
||||||
var EsApis = make(map[string][]string)
|
var EsApis = make(map[string][]string)
|
||||||
|
@ -38,33 +41,37 @@ type ConsolePermisson struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r ConsoleRole) ListPermission() interface{} {
|
func (r ConsoleRole) ListPermission() interface{} {
|
||||||
list := []ConsolePermisson{
|
//list := []ConsolePermisson{
|
||||||
{
|
// {
|
||||||
Id: "cluster_overview",
|
// Id: "cluster_overview",
|
||||||
Name: "平台概览",
|
// Name: "平台概览",
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
Id: "cluster_search",
|
// Id: "cluster_search",
|
||||||
Name: "平台搜索",
|
// Name: "平台搜索",
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
Id: "cluster_elasticsearch",
|
// Id: "cluster_elasticsearch",
|
||||||
Name: "集群监控",
|
// Name: "集群监控",
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
Id: "cluster_elasticsearch_refresh",
|
// Id: "cluster_elasticsearch_refresh",
|
||||||
Name: "集群监控刷新",
|
// Name: "集群监控刷新",
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
Id: "cluster_activities",
|
// Id: "cluster_activities",
|
||||||
Name: "集群动态",
|
// Name: "集群动态",
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
Id: "cluster_activities_search",
|
// Id: "cluster_activities_search",
|
||||||
Name: "集群动态搜索",
|
// Name: "集群动态搜索",
|
||||||
},
|
// },
|
||||||
}
|
//
|
||||||
return list
|
//}
|
||||||
|
m := make(map[string]map[string][]string)
|
||||||
|
m["api"]["用户管理"] = enum.AdminUser
|
||||||
|
m["api"]["角色管理"] = enum.AdminRole
|
||||||
|
return m
|
||||||
}
|
}
|
||||||
func (r ElasticsearchRole) ListPermission() interface{} {
|
func (r ElasticsearchRole) ListPermission() interface{} {
|
||||||
list := ElasticsearchPermisson{
|
list := ElasticsearchPermisson{
|
||||||
|
|
|
@ -5,13 +5,11 @@ import (
|
||||||
"infini.sh/console/internal/dto"
|
"infini.sh/console/internal/dto"
|
||||||
"infini.sh/console/model/rbac"
|
"infini.sh/console/model/rbac"
|
||||||
"infini.sh/framework/core/event"
|
"infini.sh/framework/core/event"
|
||||||
log "src/github.com/cihub/seelog"
|
"infini.sh/framework/core/orm"
|
||||||
|
|
||||||
"infini.sh/framework/core/util"
|
"infini.sh/framework/core/util"
|
||||||
|
log "src/github.com/cihub/seelog"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"infini.sh/framework/core/orm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateRole(localUser *User, req dto.CreateRole) (id string, err error) {
|
func CreateRole(localUser *User, req dto.CreateRole) (id string, err error) {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package biz
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
"infini.sh/console/internal/dto"
|
"infini.sh/console/internal/dto"
|
||||||
"infini.sh/console/model/rbac"
|
"infini.sh/console/model/rbac"
|
||||||
"infini.sh/framework/core/event"
|
"infini.sh/framework/core/event"
|
||||||
|
@ -73,10 +74,15 @@ func CreateUser(localUser *User, req dto.CreateUser) (id string, err error) {
|
||||||
Name: v.Name,
|
Name: v.Name,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
hash, err := bcrypt.GenerateFromPassword([]byte("123456"), bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
user := rbac.User{
|
user := rbac.User{
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
Username: req.Username,
|
Username: req.Username,
|
||||||
Password: util.MD5digest(req.Password),
|
Password: string(hash),
|
||||||
Email: req.Email,
|
Email: req.Email,
|
||||||
Phone: req.Phone,
|
Phone: req.Phone,
|
||||||
Roles: roles,
|
Roles: roles,
|
||||||
|
|
|
@ -4,3 +4,7 @@ type Login struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
|
type UpdatePassword struct {
|
||||||
|
OldPassword string `json:"oldPassword"`
|
||||||
|
NewPassword string `json:"newPassword"`
|
||||||
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ func LoginRequired(h httprouter.Handle) httprouter.Handle {
|
||||||
|
|
||||||
claims, err := biz.ValidateLogin(r.Header.Get("Authorization"))
|
claims, err := biz.ValidateLogin(r.Header.Get("Authorization"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w = handleError(w, err)
|
w = handleError(w, http.StatusUnauthorized, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r = r.WithContext(biz.NewUserContext(r.Context(), claims))
|
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) {
|
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||||
claims, err := biz.ValidateLogin(r.Header.Get("Authorization"))
|
claims, err := biz.ValidateLogin(r.Header.Get("Authorization"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w = handleError(w, err)
|
|
||||||
|
w = handleError(w, http.StatusUnauthorized, err)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = biz.ValidatePermission(claims, permissions)
|
err = biz.ValidatePermission(claims, permissions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w = handleError(w, err)
|
w = handleError(w, http.StatusForbidden, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r = r.WithContext(biz.NewUserContext(r.Context(), claims))
|
r = r.WithContext(biz.NewUserContext(r.Context(), claims))
|
||||||
h(w, r, ps)
|
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.Header().Set("Content-type", util.ContentTypeJson)
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
w.WriteHeader(statusCode)
|
||||||
w.Write([]byte(`{"error":"` + err.Error() + `"}`))
|
json := util.ToJson(util.MapStr{
|
||||||
|
"error": util.MapStr{
|
||||||
|
"status": statusCode,
|
||||||
|
"reason": err.Error(),
|
||||||
|
},
|
||||||
|
}, true)
|
||||||
|
w.Write([]byte(json))
|
||||||
|
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ func init() {
|
||||||
|
|
||||||
api.HandleAPIMethod(api.DELETE, "/account/logout", account.Logout)
|
api.HandleAPIMethod(api.DELETE, "/account/logout", account.Logout)
|
||||||
api.HandleAPIMethod(api.GET, "/account/profile", m.LoginRequired(account.Profile))
|
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"
|
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)
|
h.WriteJSON(w, reqUser, 200)
|
||||||
return
|
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",
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue