support api proxy for amap

This commit is contained in:
MaysWind
2023-06-18 09:38:21 +08:00
parent 4f2b9d39da
commit fa68621b41
21 changed files with 289 additions and 94 deletions
+34 -14
View File
@@ -152,27 +152,35 @@ func startWebServer(c *cli.Context) error {
}
}
if config.MapProvider == settings.AmapProvider && config.AmapSecurityVerificationMethod == settings.AmapSecurityVerificationInternalProxyMethod {
amapApiProxyRoute := router.Group("/_AMapService")
amapApiProxyRoute.Use(bindMiddleware(middlewares.JWTAuthorizationByCookie))
{
amapApiProxyRoute.GET("/*action", bindProxy(api.AmapApis.AmapApiProxyHandler))
}
}
apiRoute := router.Group("/api")
apiRoute.Use(bindMiddleware(middlewares.RequestId(config)))
apiRoute.Use(bindMiddleware(middlewares.RequestLog))
{
apiRoute.POST("/authorize.json", bindApi(api.Authorizations.AuthorizeHandler))
apiRoute.POST("/authorize.json", bindApiWithTokenUpdate(api.Authorizations.AuthorizeHandler, config))
if config.EnableTwoFactor {
twoFactorRoute := apiRoute.Group("/2fa")
twoFactorRoute.Use(bindMiddleware(middlewares.JWTTwoFactorAuthorization))
{
twoFactorRoute.POST("/authorize.json", bindApi(api.Authorizations.TwoFactorAuthorizeHandler))
twoFactorRoute.POST("/recovery.json", bindApi(api.Authorizations.TwoFactorAuthorizeByRecoveryCodeHandler))
twoFactorRoute.POST("/authorize.json", bindApiWithTokenUpdate(api.Authorizations.TwoFactorAuthorizeHandler, config))
twoFactorRoute.POST("/recovery.json", bindApiWithTokenUpdate(api.Authorizations.TwoFactorAuthorizeByRecoveryCodeHandler, config))
}
}
if config.EnableUserRegister {
apiRoute.POST("/register.json", bindApi(api.Users.UserRegisterHandler))
apiRoute.POST("/register.json", bindApiWithTokenUpdate(api.Users.UserRegisterHandler, config))
}
apiRoute.GET("/logout.json", bindApi(api.Tokens.TokenRevokeCurrentHandler))
apiRoute.GET("/logout.json", bindApiWithTokenUpdate(api.Tokens.TokenRevokeCurrentHandler, config))
apiV1Route := apiRoute.Group("/v1")
apiV1Route.Use(bindMiddleware(middlewares.JWTAuthorization))
@@ -181,17 +189,17 @@ func startWebServer(c *cli.Context) error {
apiV1Route.GET("/tokens/list.json", bindApi(api.Tokens.TokenListHandler))
apiV1Route.POST("/tokens/revoke.json", bindApi(api.Tokens.TokenRevokeHandler))
apiV1Route.POST("/tokens/revoke_all.json", bindApi(api.Tokens.TokenRevokeAllHandler))
apiV1Route.POST("/tokens/refresh.json", bindApi(api.Tokens.TokenRefreshHandler))
apiV1Route.POST("/tokens/refresh.json", bindApiWithTokenUpdate(api.Tokens.TokenRefreshHandler, config))
// Users
apiV1Route.GET("/users/profile/get.json", bindApi(api.Users.UserProfileHandler))
apiV1Route.POST("/users/profile/update.json", bindApi(api.Users.UserUpdateProfileHandler))
apiV1Route.POST("/users/profile/update.json", bindApiWithTokenUpdate(api.Users.UserUpdateProfileHandler, config))
// Two Factor Authorization
if config.EnableTwoFactor {
apiV1Route.GET("/users/2fa/status.json", bindApi(api.TwoFactorAuthorizations.TwoFactorStatusHandler))
apiV1Route.POST("/users/2fa/enable/request.json", bindApi(api.TwoFactorAuthorizations.TwoFactorEnableRequestHandler))
apiV1Route.POST("/users/2fa/enable/confirm.json", bindApi(api.TwoFactorAuthorizations.TwoFactorEnableConfirmHandler))
apiV1Route.POST("/users/2fa/enable/confirm.json", bindApiWithTokenUpdate(api.TwoFactorAuthorizations.TwoFactorEnableConfirmHandler, config))
apiV1Route.POST("/users/2fa/disable.json", bindApi(api.TwoFactorAuthorizations.TwoFactorDisableHandler))
apiV1Route.POST("/users/2fa/recovery/regenerate.json", bindApi(api.TwoFactorAuthorizations.TwoFactorRecoveryCodeRegenerateHandler))
}
@@ -291,6 +299,23 @@ func bindApi(fn core.ApiHandlerFunc) gin.HandlerFunc {
}
}
func bindApiWithTokenUpdate(fn core.ApiHandlerFunc, config *settings.Config) gin.HandlerFunc {
return func(ginCtx *gin.Context) {
c := core.WrapContext(ginCtx)
result, err := fn(c)
if err == nil && config.MapProvider == settings.AmapProvider && config.AmapSecurityVerificationMethod == settings.AmapSecurityVerificationInternalProxyMethod {
middlewares.AmapApiProxyAuthCookie(c, config)
}
if err != nil {
utils.PrintJsonErrorResult(c, err)
} else {
utils.PrintJsonSuccessResult(c, result)
}
}
}
func bindCsv(fn core.DataHandlerFunc) gin.HandlerFunc {
return func(ginCtx *gin.Context) {
c := core.WrapContext(ginCtx)
@@ -307,12 +332,7 @@ func bindCsv(fn core.DataHandlerFunc) gin.HandlerFunc {
func bindProxy(fn core.ProxyHandlerFunc) gin.HandlerFunc {
return func(ginCtx *gin.Context) {
c := core.WrapContext(ginCtx)
proxy, err := fn(c)
if err != nil {
utils.PrintDataErrorResult(c, "text/text", err)
} else {
proxy := fn(c)
proxy.ServeHTTP(c.Writer, c.Request)
}
}
}
+10 -3
View File
@@ -126,12 +126,19 @@ baidu_map_ak =
# For "amap" only, Amap JavaScript API application key, please visit https://lbs.amap.com/api/javascript-api/guide/abc/prepare for more information
amap_application_key =
# For "amap" only, Amap JavaScript API security verification method, supports "plain" (not recommend).
amap_security_verification_method = plain
# For "amap" only, Amap JavaScript API security verification method, supports the following methods:
# "internal_proxy": use the internal proxy to request amap api with amap application secret (default)
# "external_proxy": use an external proxy to request amap api (amap application secret should be set by external proxy)
# "plain_text": append amap application secret directly to frontend request (insecurity for public network)
# Please visit https://developer.amap.com/api/jsapi-v2/guide/abc/load for more information
amap_security_verification_method = plain_text
# For "amap" only, Amap JavaScript API application secret, this setting must be provided when "amap_security_verification_method" is set to "plain", please visit https://lbs.amap.com/api/javascript-api/guide/abc/prepare for more information
# For "amap" only, Amap JavaScript API application secret, this setting must be provided when "amap_security_verification_method" is set to "internal_proxy" or "plain_text", please visit https://lbs.amap.com/api/javascript-api/guide/abc/prepare for more information
amap_application_secret =
# For "amap" only, Amap JavaScript API external proxy url, this setting must be provided when "amap_security_verification_method" is set to "external_proxy"
amap_api_external_proxy_url =
[exchange_rates]
# Exchange rates data source, supports the following types:
# "euro_central_bank"
+60
View File
@@ -0,0 +1,60 @@
package api
import (
"fmt"
"net/http"
"net/http/httputil"
"net/url"
"strings"
"github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/settings"
)
const amapCustomMapStylesUrl = "https://webapi.amap.com/v4/map/styles"
const amapOverseasMapUrl = "https://fmap01.amap.com/v3/vectormap"
const amapRestApiUrl = "https://restapi.amap.com/"
// AmapApiProxy represents amap api proxy
type AmapApiProxy struct {
}
// Initialize a amap api proxy singleton instance
var (
AmapApis = &AmapApiProxy{}
)
// AmapApiProxyHandler returns amap api response
func (p *AmapApiProxy) AmapApiProxyHandler(c *core.Context) *httputil.ReverseProxy {
var targetUrl string
if strings.HasPrefix(c.Request.RequestURI, "/_AMapService/v4/map/styles") {
targetUrl = amapCustomMapStylesUrl + strings.TrimPrefix(c.Request.URL.Path, "/_AMapService/v4/map/styles")
} else if strings.HasPrefix(c.Request.RequestURI, "/_AMapService/v3/vectormap") {
targetUrl = amapOverseasMapUrl + strings.TrimPrefix(c.Request.URL.Path, "/_AMapService/v3/vectormap")
} else {
targetUrl = amapRestApiUrl + strings.TrimPrefix(c.Request.URL.Path, "/_AMapService/")
}
director := func(req *http.Request) {
targetRawUrl := fmt.Sprintf("%s?%s&jscode=%s", targetUrl, req.URL.RawQuery, settings.Container.Current.AmapApplicationSecret)
targetUrl, _ := url.Parse(targetRawUrl)
oldCookies := req.Cookies()
req.Header.Del("Cookie")
for i := 0; i < len(oldCookies); i++ {
if strings.HasPrefix(oldCookies[i].Name, "ebk_") {
continue
}
req.AddCookie(oldCookies[i])
}
req.URL = targetUrl
req.RequestURI = req.URL.RequestURI()
req.Host = targetUrl.Host
}
return &httputil.ReverseProxy{Director: director}
}
+6
View File
@@ -74,6 +74,10 @@ func (a *AuthorizationsApi) AuthorizeHandler(c *core.Context) (interface{}, *err
return nil, errs.ErrTokenGenerating
}
if !twoFactorEnable {
c.SetTextualToken(token)
}
c.SetTokenClaims(claims)
log.InfofWithRequestId(c, "[authorizations.AuthorizeHandler] user \"uid:%d\" has logined, token type is %d, token will be expired at %d", user.Uid, claims.Type, claims.ExpiresAt)
@@ -126,6 +130,7 @@ func (a *AuthorizationsApi) TwoFactorAuthorizeHandler(c *core.Context) (interfac
return nil, errs.ErrTokenGenerating
}
c.SetTextualToken(token)
c.SetTokenClaims(claims)
log.InfofWithRequestId(c, "[authorizations.TwoFactorAuthorizeHandler] user \"uid:%d\" has authorized two factor via passcode, token will be expired at %d", user.Uid, claims.ExpiresAt)
@@ -184,6 +189,7 @@ func (a *AuthorizationsApi) TwoFactorAuthorizeByRecoveryCodeHandler(c *core.Cont
return nil, errs.ErrTokenGenerating
}
c.SetTextualToken(token)
c.SetTokenClaims(claims)
log.InfofWithRequestId(c, "[authorizations.TwoFactorAuthorizeByRecoveryCodeHandler] user \"uid:%d\" has authorized two factor via recovery code \"%s\", token will be expired at %d", user.Uid, credential.RecoveryCode, claims.ExpiresAt)
+2 -3
View File
@@ -7,7 +7,6 @@ import (
"net/url"
"github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/errs"
)
const openStreetMapTileImageUrlFormat = "https://tile.openstreetmap.org/%s/%s/%s" // https://tile.openstreetmap.org/{z}/{x}/{y}.png
@@ -22,7 +21,7 @@ var (
)
// OpenStreetMapTileImageProxyHandler returns open street map tile image
func (p *MapImageProxy) OpenStreetMapTileImageProxyHandler(c *core.Context) (*httputil.ReverseProxy, *errs.Error) {
func (p *MapImageProxy) OpenStreetMapTileImageProxyHandler(c *core.Context) *httputil.ReverseProxy {
director := func(req *http.Request) {
zoomLevel := c.Param("zoomLevel")
coordinateX := c.Param("coordinateX")
@@ -36,5 +35,5 @@ func (p *MapImageProxy) OpenStreetMapTileImageProxyHandler(c *core.Context) (*ht
req.Host = imageUrl.Host
}
return &httputil.ReverseProxy{Director: director}, nil
return &httputil.ReverseProxy{Director: director}
}
+1
View File
@@ -191,6 +191,7 @@ func (a *TokensApi) TokenRefreshHandler(c *core.Context) (interface{}, *errs.Err
CreatedUnixTime: oldTokenClaims.IssuedAt,
}
c.SetTextualToken(token)
c.SetTokenClaims(claims)
log.InfofWithRequestId(c, "[token.TokenRefreshHandler] user \"uid:%d\" token refreshed, new token will be expired at %d", user.Uid, claims.ExpiresAt)
+1
View File
@@ -195,6 +195,7 @@ func (a *TwoFactorAuthorizationsApi) TwoFactorEnableConfirmHandler(c *core.Conte
return confirmResp, nil
}
c.SetTextualToken(token)
c.SetTokenClaims(claims)
log.InfofWithRequestId(c, "[twofactor_authorizations.TwoFactorEnableConfirmHandler] user \"uid:%d\" token refreshed, new token will be expired at %d", user.Uid, claims.ExpiresAt)
+2
View File
@@ -85,6 +85,7 @@ func (a *UsersApi) UserRegisterHandler(c *core.Context) (interface{}, *errs.Erro
}
authResp.Token = token
c.SetTextualToken(token)
c.SetTokenClaims(claims)
log.InfofWithRequestId(c, "[users.UserRegisterHandler] user \"uid:%d\" has logined, token will be expired at %d", user.Uid, claims.ExpiresAt)
@@ -272,6 +273,7 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.Context) (interface{}, *errs
}
resp.NewToken = token
c.SetTextualToken(token)
c.SetTokenClaims(claims)
log.InfofWithRequestId(c, "[users.UserUpdateProfileHandler] user \"uid:%d\" token refreshed, new token will be expired at %d", user.Uid, claims.ExpiresAt)
+18 -1
View File
@@ -9,6 +9,7 @@ import (
)
const requestIdFieldKey = "REQUEST_ID"
const textualTokenFieldKey = "TOKEN_STRING"
const tokenClaimsFieldKey = "TOKEN_CLAIMS"
const responseErrorFieldKey = "RESPONSE_ERROR"
@@ -37,7 +38,23 @@ func (c *Context) GetRequestId() string {
return requestId.(string)
}
// SetTokenClaims sets the given user token id to context
// SetTextualToken sets the given user token to context
func (c *Context) SetTextualToken(token string) {
c.Set(textualTokenFieldKey, token)
}
// GetTextualToken returns the current user textual token
func (c *Context) GetTextualToken() string {
token, exists := c.Get(textualTokenFieldKey)
if !exists {
return ""
}
return token.(string)
}
// SetTokenClaims sets the given user token to context
func (c *Context) SetTokenClaims(claims *UserTokenClaims) {
c.Set(tokenClaimsFieldKey, claims)
}
+1 -1
View File
@@ -16,4 +16,4 @@ type ApiHandlerFunc func(*Context) (interface{}, *errs.Error)
type DataHandlerFunc func(*Context) ([]byte, string, *errs.Error)
// ProxyHandlerFunc represents the reverse proxy handler function
type ProxyHandlerFunc func(*Context) (*httputil.ReverseProxy, *errs.Error)
type ProxyHandlerFunc func(*Context) *httputil.ReverseProxy
@@ -0,0 +1,19 @@
package middlewares
import (
"github.com/mayswind/ezbookkeeping/pkg/core"
"github.com/mayswind/ezbookkeeping/pkg/settings"
)
const tokenCookieParam = "ebk_auth_token"
// AmapApiProxyAuthCookie adds amap api proxy auth cookie to cookies in response
func AmapApiProxyAuthCookie(c *core.Context, config *settings.Config) {
token := c.GetTextualToken()
if token != "" {
c.SetCookie(tokenCookieParam, token, int(config.TokenExpiredTime), "/_AMapService", "", false, true)
} else {
c.SetCookie(tokenCookieParam, "", -1, "/_AMapService", "", false, true)
}
}
+34 -42
View File
@@ -17,58 +17,24 @@ type TokenSourceType byte
const (
TOKEN_SOURCE_TYPE_HEADER TokenSourceType = 1
TOKEN_SOURCE_TYPE_ARGUMENT TokenSourceType = 2
TOKEN_SOURCE_TYPE_COOKIE TokenSourceType = 3
)
const tokenQueryStringParam = "token"
// JWTAuthorization verifies whether current request is valid by jwt token
// JWTAuthorization verifies whether current request is valid by jwt token in header
func JWTAuthorization(c *core.Context) {
claims, err := getTokenClaims(c, TOKEN_SOURCE_TYPE_HEADER)
if err != nil {
utils.PrintJsonErrorResult(c, err)
return
jwtAuthorization(c, TOKEN_SOURCE_TYPE_HEADER)
}
if claims.Type == core.USER_TOKEN_TYPE_REQUIRE_2FA {
log.WarnfWithRequestId(c, "[authorization.JWTAuthorization] user \"uid:%d\" token requires 2fa", claims.Uid)
utils.PrintJsonErrorResult(c, errs.ErrCurrentTokenRequire2FA)
return
}
if claims.Type != core.USER_TOKEN_TYPE_NORMAL {
log.WarnfWithRequestId(c, "[authorization.JWTAuthorization] user \"uid:%d\" token type is invalid", claims.Uid)
utils.PrintJsonErrorResult(c, errs.ErrCurrentInvalidTokenType)
return
}
c.SetTokenClaims(claims)
c.Next()
}
// JWTAuthorizationByQueryString verifies whether current request is valid by jwt token
// JWTAuthorizationByQueryString verifies whether current request is valid by jwt token in query string
func JWTAuthorizationByQueryString(c *core.Context) {
claims, err := getTokenClaims(c, TOKEN_SOURCE_TYPE_ARGUMENT)
if err != nil {
utils.PrintJsonErrorResult(c, err)
return
jwtAuthorization(c, TOKEN_SOURCE_TYPE_ARGUMENT)
}
if claims.Type == core.USER_TOKEN_TYPE_REQUIRE_2FA {
log.WarnfWithRequestId(c, "[authorization.JWTAuthorizationByQueryString] user \"uid:%d\" token requires 2fa", claims.Uid)
utils.PrintJsonErrorResult(c, errs.ErrCurrentTokenRequire2FA)
return
}
if claims.Type != core.USER_TOKEN_TYPE_NORMAL {
log.WarnfWithRequestId(c, "[authorization.JWTAuthorizationByQueryString] user \"uid:%d\" token type is invalid", claims.Uid)
utils.PrintJsonErrorResult(c, errs.ErrCurrentInvalidTokenType)
return
}
c.SetTokenClaims(claims)
c.Next()
// JWTAuthorizationByCookie verifies whether current request is valid by jwt token in cookie
func JWTAuthorizationByCookie(c *core.Context) {
jwtAuthorization(c, TOKEN_SOURCE_TYPE_COOKIE)
}
// JWTTwoFactorAuthorization verifies whether current request is valid by 2fa passcode
@@ -90,6 +56,30 @@ func JWTTwoFactorAuthorization(c *core.Context) {
c.Next()
}
func jwtAuthorization(c *core.Context, source TokenSourceType) {
claims, err := getTokenClaims(c, source)
if err != nil {
utils.PrintJsonErrorResult(c, err)
return
}
if claims.Type == core.USER_TOKEN_TYPE_REQUIRE_2FA {
log.WarnfWithRequestId(c, "[authorization.jwtAuthorization] user \"uid:%d\" token requires 2fa", claims.Uid)
utils.PrintJsonErrorResult(c, errs.ErrCurrentTokenRequire2FA)
return
}
if claims.Type != core.USER_TOKEN_TYPE_NORMAL {
log.WarnfWithRequestId(c, "[authorization.jwtAuthorization] user \"uid:%d\" token type is invalid", claims.Uid)
utils.PrintJsonErrorResult(c, errs.ErrCurrentInvalidTokenType)
return
}
c.SetTokenClaims(claims)
c.Next()
}
func getTokenClaims(c *core.Context, source TokenSourceType) (*core.UserTokenClaims, *errs.Error) {
token, claims, err := parseToken(c, source)
@@ -114,6 +104,8 @@ func getTokenClaims(c *core.Context, source TokenSourceType) (*core.UserTokenCla
func parseToken(c *core.Context, source TokenSourceType) (*jwt.Token, *core.UserTokenClaims, error) {
if source == TOKEN_SOURCE_TYPE_ARGUMENT {
return services.Tokens.ParseTokenByArgument(c, tokenQueryStringParam)
} else if source == TOKEN_SOURCE_TYPE_COOKIE {
return services.Tokens.ParseTokenByCookie(c, tokenCookieParam)
}
return services.Tokens.ParseTokenByHeader(c)
+24 -12
View File
@@ -1,7 +1,9 @@
package middlewares
import (
"encoding/base64"
"fmt"
"net/url"
"strings"
"github.com/mayswind/ezbookkeeping/pkg/core"
@@ -19,27 +21,31 @@ func ServerSettingsCookie(config *settings.Config) core.MiddlewareHandlerFunc {
buildStringSetting("m", config.MapProvider),
}
if config.EnableMapDataFetchProxy {
if config.MapProvider == settings.OpenStreetMapProvider && config.EnableMapDataFetchProxy {
settingsArr = append(settingsArr, buildBooleanSetting("mp", config.EnableMapDataFetchProxy))
}
if config.GoogleMapAPIKey != "" {
settingsArr = append(settingsArr, buildStringSetting("gmak", config.GoogleMapAPIKey))
if config.MapProvider == settings.GoogleMapProvider && config.GoogleMapAPIKey != "" {
settingsArr = append(settingsArr, buildEncodedStringSetting("gmak", config.GoogleMapAPIKey))
}
if config.BaiduMapAK != "" {
settingsArr = append(settingsArr, buildStringSetting("bmak", config.BaiduMapAK))
if config.MapProvider == settings.BaiduMapProvider && config.BaiduMapAK != "" {
settingsArr = append(settingsArr, buildEncodedStringSetting("bmak", config.BaiduMapAK))
}
if config.AMapApplicationKey != "" {
settingsArr = append(settingsArr, buildStringSetting("amak", config.AMapApplicationKey))
if config.MapProvider == settings.AmapProvider && config.AmapApplicationKey != "" {
settingsArr = append(settingsArr, buildEncodedStringSetting("amak", config.AmapApplicationKey))
}
if config.AMapSecurityVerificationMethod != "" {
settingsArr = append(settingsArr, buildStringSetting("amsv", config.AMapSecurityVerificationMethod))
if config.MapProvider == settings.AmapProvider && config.AmapSecurityVerificationMethod != "" {
settingsArr = append(settingsArr, buildStringSetting("amsv", strings.Replace(config.AmapSecurityVerificationMethod, "_", "", -1)))
if config.AMapSecurityVerificationMethod == settings.AmapSecurityVerificationPlainMethod {
settingsArr = append(settingsArr, buildStringSetting("amas", config.AMapApplicationSecret))
if config.AmapSecurityVerificationMethod == settings.AmapSecurityVerificationExternalProxyMethod {
settingsArr = append(settingsArr, buildEncodedStringSetting("amep", config.AmapApiExternalProxyUrl))
}
if config.AmapSecurityVerificationMethod == settings.AmapSecurityVerificationPlainTextMethod {
settingsArr = append(settingsArr, buildEncodedStringSetting("amas", config.AmapApplicationSecret))
}
}
@@ -51,7 +57,13 @@ func ServerSettingsCookie(config *settings.Config) core.MiddlewareHandlerFunc {
}
func buildStringSetting(key string, value string) string {
return fmt.Sprintf("%s.%s", key, strings.Replace(value, ".", "-", -1))
return fmt.Sprintf("%s.%s", key, value)
}
func buildEncodedStringSetting(key string, value string) string {
urlEncodedValue := url.QueryEscape(value)
base64Value := base64.StdEncoding.EncodeToString([]byte(urlEncodedValue))
return fmt.Sprintf("%s.%s", key, base64Value)
}
func buildBooleanSetting(key string, value bool) string {
+5
View File
@@ -73,6 +73,11 @@ func (s *TokenService) ParseTokenByArgument(c *core.Context, tokenParameterName
return s.parseToken(c, request.ArgumentExtractor{tokenParameterName})
}
// ParseTokenByCookie returns the token model according to request data
func (s *TokenService) ParseTokenByCookie(c *core.Context, tokenCookieName string) (*jwt.Token, *core.UserTokenClaims, error) {
return s.parseToken(c, utils.CookieExtractor{tokenCookieName})
}
// CreateToken generates a new normal token and saves to database
func (s *TokenService) CreateToken(user *models.User, ctx *core.Context) (string, *core.UserTokenClaims, error) {
return s.createToken(user, core.USER_TOKEN_TYPE_NORMAL, s.getUserAgent(ctx), s.CurrentConfig().TokenExpiredTimeDuration)
+16 -8
View File
@@ -72,7 +72,9 @@ const (
// Amap security verification method
const (
AmapSecurityVerificationPlainMethod string = "plain"
AmapSecurityVerificationInternalProxyMethod string = "internal_proxy"
AmapSecurityVerificationExternalProxyMethod string = "external_proxy"
AmapSecurityVerificationPlainTextMethod string = "plain_text"
)
// Exchange rates data source types
@@ -186,9 +188,10 @@ type Config struct {
MapProvider string
GoogleMapAPIKey string
BaiduMapAK string
AMapApplicationKey string
AMapSecurityVerificationMethod string
AMapApplicationSecret string
AmapApplicationKey string
AmapSecurityVerificationMethod string
AmapApplicationSecret string
AmapApiExternalProxyUrl string
EnableMapDataFetchProxy bool
// Exchange Rates
@@ -462,15 +465,20 @@ func loadMapConfiguration(config *Config, configFile *ini.File, sectionName stri
config.EnableMapDataFetchProxy = getConfigItemBoolValue(configFile, sectionName, "map_data_fetch_proxy", false)
config.GoogleMapAPIKey = getConfigItemStringValue(configFile, sectionName, "google_map_api_key")
config.BaiduMapAK = getConfigItemStringValue(configFile, sectionName, "baidu_map_ak")
config.AMapApplicationKey = getConfigItemStringValue(configFile, sectionName, "amap_application_key")
config.AmapApplicationKey = getConfigItemStringValue(configFile, sectionName, "amap_application_key")
if getConfigItemStringValue(configFile, sectionName, "amap_security_verification_method") == AmapSecurityVerificationPlainMethod {
config.AMapSecurityVerificationMethod = AmapSecurityVerificationPlainMethod
if getConfigItemStringValue(configFile, sectionName, "amap_security_verification_method") == AmapSecurityVerificationInternalProxyMethod {
config.AmapSecurityVerificationMethod = AmapSecurityVerificationInternalProxyMethod
} else if getConfigItemStringValue(configFile, sectionName, "amap_security_verification_method") == AmapSecurityVerificationExternalProxyMethod {
config.AmapSecurityVerificationMethod = AmapSecurityVerificationExternalProxyMethod
} else if getConfigItemStringValue(configFile, sectionName, "amap_security_verification_method") == AmapSecurityVerificationPlainTextMethod {
config.AmapSecurityVerificationMethod = AmapSecurityVerificationPlainTextMethod
} else {
return errs.ErrInvalidAmapSecurityVerificationMethod
}
config.AMapApplicationSecret = getConfigItemStringValue(configFile, sectionName, "amap_application_secret")
config.AmapApplicationSecret = getConfigItemStringValue(configFile, sectionName, "amap_application_secret")
config.AmapApiExternalProxyUrl = getConfigItemStringValue(configFile, sectionName, "amap_api_external_proxy_url")
return nil
}
+20
View File
@@ -0,0 +1,20 @@
package utils
import (
"net/http"
"github.com/golang-jwt/jwt/v5/request"
)
// CookieExtractor extracts a token from request cookies
type CookieExtractor []string
func (e CookieExtractor) ExtractToken(req *http.Request) (string, error) {
for _, arg := range e {
if cookie, _ := req.Cookie(arg); cookie != nil {
return cookie.Value, nil
}
}
return "", request.ErrNoTokenInRequest
}
+2
View File
@@ -1,5 +1,6 @@
const baseApiUrlPath = '/api';
const baseProxyUrlPath = '/proxy';
const baseAmapApiProxyUrlPath = '/_AMapService';
const googleMapJavascriptUrl = 'https://maps.googleapis.com/maps/api/js';
const baiduMapJavascriptUrl = 'https://api.map.baidu.com/api?v=3.0';
const amapJavascriptUrl = 'https://webapi.amap.com/maps?v=2.0';
@@ -7,6 +8,7 @@ const amapJavascriptUrl = 'https://webapi.amap.com/maps?v=2.0';
export default {
baseApiUrlPath: baseApiUrlPath,
baseProxyUrlPath: baseProxyUrlPath,
baseAmapApiProxyUrlPath: baseAmapApiProxyUrlPath,
googleMapJavascriptUrl: googleMapJavascriptUrl,
baiduMapJavascriptUrl: baiduMapJavascriptUrl,
amapJavascriptUrl: amapJavascriptUrl
+8 -4
View File
@@ -1,6 +1,6 @@
import { asyncLoadAssets } from "@/lib/misc.js";
import services from "@/lib/services.js";
import settings from "@/lib/settings.js";
import { asyncLoadAssets } from '@/lib/misc.js';
import services from '@/lib/services.js';
import settings from '@/lib/settings.js';
import logger from '@/lib/logger.js';
const amapHolder = {
@@ -15,7 +15,11 @@ export function loadAmapAssets() {
if (!window._AMapSecurityConfig) {
const amapSecurityConfig = {};
if (settings.getAmapSecurityVerificationMethod() === 'plain') {
if (settings.getAmapSecurityVerificationMethod() === 'internalproxy') {
amapSecurityConfig.serviceHost = services.generateAmapApiInternalProxyUrl();
} else if (settings.getAmapSecurityVerificationMethod() === 'externalproxy') {
amapSecurityConfig.serviceHost = settings.getAmapApiExternalProxyUrl();
} else if (settings.getAmapSecurityVerificationMethod() === 'plaintext') {
amapSecurityConfig.securityJsCode = settings.getAmapApplicationSecret();
}
+3
View File
@@ -423,5 +423,8 @@ export default {
},
generateAmapJavascriptUrl: (callbackFnName) => {
return `${api.amapJavascriptUrl}&key=${settings.getAmapApplicationKey()}&callback=${callbackFnName}`;
},
generateAmapApiInternalProxyUrl: () => {
return `${window.location.origin}${api.baseAmapApiProxyUrlPath}`;
}
};
+17 -4
View File
@@ -3,6 +3,8 @@ import Cookies from 'js-cookie';
import currencyConstants from '@/consts/currency.js';
import statisticsConstants from '@/consts/statistics.js';
import { base64decode } from '@/lib/common.js';
const settingsLocalStorageKey = 'ebk_app_settings';
const serverSettingsCookieKey = 'ebk_server_settings';
@@ -119,6 +121,16 @@ function getServerSetting(key) {
return undefined;
}
function getServerDecodedSetting(key) {
const value = getServerSetting(key);
if (!value) {
return value;
}
return decodeURIComponent(base64decode(value));
}
function clearSettings() {
localStorage.removeItem(settingsLocalStorageKey);
}
@@ -169,10 +181,11 @@ export default {
isDataExportingEnabled: () => getServerSetting('e') === '1',
getMapProvider: () => getServerSetting('m'),
isMapDataFetchProxyEnabled: () => getServerSetting('mp') === '1',
getGoogleMapAPIKey: () => getServerSetting('gmak'),
getBaiduMapAK: () => getServerSetting('bmak'),
getAmapApplicationKey: () => getServerSetting('amak'),
getGoogleMapAPIKey: () => getServerDecodedSetting('gmak'),
getBaiduMapAK: () => getServerDecodedSetting('bmak'),
getAmapApplicationKey: () => getServerDecodedSetting('amak'),
getAmapSecurityVerificationMethod: () => getServerSetting('amsv'),
getAmapApplicationSecret: () => getServerSetting('amas'),
getAmapApiExternalProxyUrl: () => getServerDecodedSetting('amep'),
getAmapApplicationSecret: () => getServerDecodedSetting('amas'),
clearSettings: clearSettings
};
+4
View File
@@ -139,6 +139,10 @@ export default defineConfig(async () => {
'/proxy': {
target: 'http://127.0.0.1:8080/',
changeOrigin: true
},
'/_AMapService': {
target: 'http://127.0.0.1:8080/',
changeOrigin: true
}
}
},