231 lines
6.5 KiB
Go
231 lines
6.5 KiB
Go
package middleware
|
||
|
||
import (
|
||
"crypto/tls"
|
||
"encoding/json"
|
||
"fmt"
|
||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/config"
|
||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/user"
|
||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/auth"
|
||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/authen"
|
||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/errors"
|
||
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/response"
|
||
"github.com/gin-gonic/gin"
|
||
"github.com/golang/glog"
|
||
"gorm.io/gorm"
|
||
"io"
|
||
"net/http"
|
||
"regexp"
|
||
)
|
||
|
||
const (
|
||
LoginUserKey = "login-user"
|
||
)
|
||
|
||
func AuthenticationHandler() gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
|
||
match, _ := regexp.MatchString("/healthz", c.Request.RequestURI)
|
||
if match {
|
||
c.Next()
|
||
return
|
||
}
|
||
match, _ = regexp.MatchString("/run", c.Request.RequestURI)
|
||
if match {
|
||
c.Next()
|
||
return
|
||
}
|
||
match, _ = regexp.MatchString("/login", c.Request.RequestURI)
|
||
if match {
|
||
c.Next()
|
||
return
|
||
}
|
||
|
||
match, _ = regexp.MatchString("/api/v1/socket/*", c.Request.RequestURI)
|
||
if match {
|
||
c.Next()
|
||
return
|
||
}
|
||
|
||
match, _ = regexp.MatchString("/api/v1/*", c.Request.RequestURI)
|
||
if match {
|
||
rawToken := c.Request.Header.Get("Authorization")
|
||
if rawToken == "" {
|
||
glog.Warning("unauthorized access, token not specified")
|
||
response.Resp().FailCode(c, errors.AuthorizationError, "token should be specified in header with 'Authorization' key")
|
||
return
|
||
}
|
||
|
||
//todo 临时用
|
||
if config.Config.AppConfig.Debug {
|
||
if rawToken == "mock token" {
|
||
u, _ := user.GetUserByUsername("admin")
|
||
c.Set(LoginUserKey, u)
|
||
c.Next()
|
||
return
|
||
}
|
||
}
|
||
|
||
var username, apiToken string
|
||
ok, bearerToken := authen.JWTAuthorizer.IsBearerToken(rawToken)
|
||
if ok {
|
||
loginInfo, err := auth.Validate(bearerToken)
|
||
//marshal, _ := json.Marshal(loginInfo)
|
||
//fmt.Print(string(marshal))
|
||
|
||
if err != nil {
|
||
if authen.JWTAuthorizer.IsTokenExpired(err) {
|
||
glog.Warning("unauthorized access, bearer token expired")
|
||
response.Resp().FailCode(c, errors.AuthorizationError, "bearer token expired")
|
||
return
|
||
}
|
||
glog.Warningf("validate bearer token failed, %s", err)
|
||
response.Resp().FailCode(c, errors.AuthorizationError, fmt.Sprint("validate bearer token failed, %s", err))
|
||
return
|
||
}
|
||
username = loginInfo.Username
|
||
apiToken = loginInfo.Token
|
||
} else {
|
||
glog.Warningf("validate bearer token failed")
|
||
response.Resp().FailCode(c, errors.AuthorizationError, "validate bearer token failed")
|
||
|
||
return
|
||
}
|
||
|
||
u, err := user.GetUserByUsername(username)
|
||
if err != nil {
|
||
// 适配算网用户,支持单点登录
|
||
if config.Config.CfnConfig.Enable {
|
||
u, err = CheckUserLogin(c)
|
||
if err != nil {
|
||
glog.Errorf("unauthorized access, user not found or not login, %s", username)
|
||
response.Resp().FailCode(c, errors.AuthorizationError, "user not found or not login")
|
||
return
|
||
}
|
||
// todo?
|
||
u.APIToken = apiToken
|
||
} else {
|
||
if err == gorm.ErrRecordNotFound {
|
||
glog.Errorf("unauthorized access, user not found, %s", username)
|
||
response.Resp().FailCode(c, errors.AuthorizationError, "user not found")
|
||
return
|
||
}
|
||
glog.Errorf("get user from db failed, user %s, %s", username, err)
|
||
response.Resp().FailCode(c, errors.ServerError, fmt.Sprintf("get user from db failed, user %s, %s", username, err))
|
||
|
||
return
|
||
}
|
||
}
|
||
|
||
if apiToken != "" && apiToken != u.APIToken {
|
||
glog.Warningf("unauthorized access, password mismatch, user %s", username)
|
||
response.Resp().FailCode(c, errors.AuthorizationError, "password mismatch")
|
||
return
|
||
}
|
||
|
||
c.Set(LoginUserKey, u)
|
||
c.Next()
|
||
}
|
||
|
||
//match, _ = regexp.MatchString("/", c.Request.RequestURI)
|
||
//if match {
|
||
// c.Next()
|
||
// return
|
||
//}
|
||
|
||
}
|
||
}
|
||
|
||
const AUTH_HEADER = "Authorization"
|
||
|
||
func CheckUserLogin(c *gin.Context) (*user.UserObj, error) {
|
||
url := config.Config.Auth.Url
|
||
if url == "" {
|
||
return nil, errors.NewBusinessError(errors.ServerError, "login config is not set!")
|
||
}
|
||
token := c.Request.Header.Get(AUTH_HEADER)
|
||
|
||
var client *http.Client
|
||
var request *http.Request
|
||
var resp *http.Response
|
||
client = &http.Client{Transport: &http.Transport{
|
||
TLSClientConfig: &tls.Config{
|
||
InsecureSkipVerify: true,
|
||
},
|
||
}}
|
||
request, err := http.NewRequest("GET", url+config.Config.Auth.LoginInfo, nil)
|
||
if err != nil {
|
||
glog.Errorln("failed to create request [Get LoginInfo]!", err)
|
||
return nil, errors.NewBusinessError(errors.ServerError, "failed to create request [Get LoginInfo]!")
|
||
}
|
||
request.Header.Add(AUTH_HEADER, token)
|
||
resp, err = client.Do(request)
|
||
if err != nil {
|
||
glog.Errorln("failed to request [Get LoginInfo]!", err)
|
||
return nil, errors.NewBusinessError(errors.ServerError, "failed to request [Get LoginInfo]!")
|
||
}
|
||
defer resp.Body.Close()
|
||
defer client.CloseIdleConnections()
|
||
if resp.StatusCode != 200 {
|
||
glog.Errorln("response error [Get LoginInfo]!")
|
||
glog.Errorln("response status code: %d, %s", resp.StatusCode, resp.Body)
|
||
return nil, errors.NewBusinessError(errors.ServerError, "response error [Get LoginInfo]!")
|
||
}
|
||
|
||
var respBody map[string]interface{}
|
||
respStr, _ := io.ReadAll(resp.Body)
|
||
err = json.Unmarshal(respStr, &respBody)
|
||
if err != nil {
|
||
glog.Errorln("failed to decode response [Get LoginInfo]!", err)
|
||
return nil, errors.NewBusinessError(errors.ServerError, "failed to decode response [Get LoginInfo]!")
|
||
}
|
||
|
||
data := respBody["data"]
|
||
if data == nil {
|
||
meta := respBody["meta"]
|
||
return nil, fmt.Errorf("failed to get user info from login server! %s", meta)
|
||
}
|
||
|
||
userObj := &user.UserObj{}
|
||
userMap := data.(map[string]interface{})["user"]
|
||
|
||
userId := userMap.(map[string]interface{})["userId"]
|
||
if userId != nil {
|
||
userObj.UserID = userId.(string)
|
||
}
|
||
|
||
cn := userMap.(map[string]interface{})["cn"]
|
||
if cn != nil {
|
||
userObj.DisplayName = cn.(string)
|
||
}
|
||
mobile := userMap.(map[string]interface{})["mobile"]
|
||
if mobile != nil {
|
||
userObj.Mobile = mobile.(string)
|
||
}
|
||
provinceId := userMap.(map[string]interface{})["provinceId"]
|
||
if provinceId != nil {
|
||
userObj.ProvinceId = provinceId.(string)
|
||
}
|
||
userObj.Status = userMap.(map[string]interface{})["status"].(string)
|
||
|
||
accountMap := data.(map[string]interface{})["account"]
|
||
userName := accountMap.(map[string]interface{})["loginName"]
|
||
if userName != nil {
|
||
userObj.UserName = userName.(string)
|
||
}
|
||
|
||
if userName == "admin" {
|
||
userObj.Role = 1
|
||
} else {
|
||
userObj.Role = 0
|
||
}
|
||
|
||
if config.Config.CfnConfig.Enable {
|
||
userObj.Namespace = fmt.Sprintf("DEFAULT,%s", config.Config.CfnConfig.CfnWorkSpaceId)
|
||
} else {
|
||
userObj.Namespace = "DEFAULT"
|
||
}
|
||
|
||
return userObj, nil
|
||
}
|