@@ -4,7 +4,7 @@ ARG BUILDARCH=amd64
|
|||||||
|
|
||||||
# Stage 1: Builder Stage
|
# Stage 1: Builder Stage
|
||||||
# FROM golang:${GO_VERSION}-alpine AS builder
|
# FROM golang:${GO_VERSION}-alpine AS builder
|
||||||
FROM crazymax/xgo:${GO_VERSION} AS builder
|
FROM crazymax/xgo:${GO_VERSION} AS builder-backend
|
||||||
|
|
||||||
# Set up working directory
|
# Set up working directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
@@ -27,7 +27,7 @@ RUN CGO_ENABLED=1 GOOS=linux go build -a \
|
|||||||
-installsuffix cgo -o release/apimain cmd/apimain.go
|
-installsuffix cgo -o release/apimain cmd/apimain.go
|
||||||
|
|
||||||
# Stage 2: Frontend Build Stage (builder2)
|
# Stage 2: Frontend Build Stage (builder2)
|
||||||
FROM node:18-alpine AS builder2
|
FROM node:18-alpine AS builder-admin-frontend
|
||||||
|
|
||||||
# Set working directory
|
# Set working directory
|
||||||
WORKDIR /frontend
|
WORKDIR /frontend
|
||||||
@@ -50,12 +50,12 @@ WORKDIR /app
|
|||||||
RUN apk add --no-cache tzdata file
|
RUN apk add --no-cache tzdata file
|
||||||
|
|
||||||
# Copy the built application and resources from the builder stage
|
# Copy the built application and resources from the builder stage
|
||||||
COPY --from=builder /app/release /app/
|
COPY --from=builder-backend /app/release /app/
|
||||||
COPY --from=builder /app/conf /app/conf/
|
COPY --from=builder-backend /app/conf /app/conf/
|
||||||
COPY --from=builder /app/resources /app/resources/
|
COPY --from=builder-backend /app/resources /app/resources/
|
||||||
COPY --from=builder /app/docs /app/docs/
|
COPY --from=builder-backend /app/docs /app/docs/
|
||||||
# Copy frontend build from builder2 stage
|
# Copy frontend build from builder2 stage
|
||||||
COPY --from=builder2 /frontend/dist/ /app/resources/admin/
|
COPY --from=builder-admin-frontend /frontend/dist/ /app/resources/admin/
|
||||||
|
|
||||||
# Ensure the binary is correctly built and linked
|
# Ensure the binary is correctly built and linked
|
||||||
RUN file /app/apimain && \
|
RUN file /app/apimain && \
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import (
|
|||||||
"Gwen/http/request/admin"
|
"Gwen/http/request/admin"
|
||||||
"Gwen/http/response"
|
"Gwen/http/response"
|
||||||
adResp "Gwen/http/response/admin"
|
adResp "Gwen/http/response/admin"
|
||||||
|
apiReq "Gwen/http/request/api"
|
||||||
|
"Gwen/http/controller/api"
|
||||||
"Gwen/model"
|
"Gwen/model"
|
||||||
"Gwen/service"
|
"Gwen/service"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -51,7 +53,7 @@ func (ct *Login) Login(c *gin.Context) {
|
|||||||
ut := service.AllService.UserService.Login(u, &model.LoginLog{
|
ut := service.AllService.UserService.Login(u, &model.LoginLog{
|
||||||
UserId: u.Id,
|
UserId: u.Id,
|
||||||
Client: "webadmin",
|
Client: "webadmin",
|
||||||
Uuid: "",
|
Uuid: "", //must be empty
|
||||||
Ip: c.ClientIP(),
|
Ip: c.ClientIP(),
|
||||||
Type: "account",
|
Type: "account",
|
||||||
Platform: f.Platform,
|
Platform: f.Platform,
|
||||||
@@ -82,3 +84,86 @@ func (ct *Login) Logout(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
response.Success(c, nil)
|
response.Success(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// LoginOptions
|
||||||
|
// @Tags 登录
|
||||||
|
// @Summary 登录选项
|
||||||
|
// @Description 登录选项
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} []string
|
||||||
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
|
// @Router /admin/login-options [post]
|
||||||
|
// 直接调用/api/login的LoginOptions方法
|
||||||
|
func (ct *Login) LoginOptions(c *gin.Context) {
|
||||||
|
l := &api.Login{}
|
||||||
|
l.LoginOptions(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// OidcAuth
|
||||||
|
// @Tags Oauth
|
||||||
|
// @Summary OidcAuth
|
||||||
|
// @Description OidcAuth
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Router /admin/oidc/auth [post]
|
||||||
|
func (ct *Login) OidcAuth(c *gin.Context) {
|
||||||
|
// o := &api.Oauth{}
|
||||||
|
// o.OidcAuth(c)
|
||||||
|
f := &apiReq.OidcAuthRequest{}
|
||||||
|
err := c.ShouldBindJSON(f)
|
||||||
|
if err != nil {
|
||||||
|
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err, code, url := service.AllService.OauthService.BeginAuth(f.Op)
|
||||||
|
if err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
service.AllService.OauthService.SetOauthCache(code, &service.OauthCacheItem{
|
||||||
|
Action: service.OauthActionTypeLogin,
|
||||||
|
Op: f.Op,
|
||||||
|
Id: f.Id,
|
||||||
|
DeviceType: "webadmin",
|
||||||
|
// DeviceOs: ct.Platform(c),
|
||||||
|
DeviceOs: f.DeviceInfo.Os,
|
||||||
|
Uuid: f.Uuid,
|
||||||
|
}, 5*60)
|
||||||
|
|
||||||
|
response.Success(c, gin.H{
|
||||||
|
"code": code,
|
||||||
|
"url": url,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// OidcAuthQuery
|
||||||
|
// @Tags Oauth
|
||||||
|
// @Summary OidcAuthQuery
|
||||||
|
// @Description OidcAuthQuery
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} response.Response{data=adResp.LoginPayload}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /admin/oidc/auth-query [get]
|
||||||
|
func (ct *Login) OidcAuthQuery(c *gin.Context) {
|
||||||
|
o := &api.Oauth{}
|
||||||
|
u, ut := o.OidcAuthQueryPre(c)
|
||||||
|
if ut == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println("u:", u)
|
||||||
|
fmt.Println("ut:", ut)
|
||||||
|
response.Success(c, &adResp.LoginPayload{
|
||||||
|
Token: ut.Token,
|
||||||
|
Username: u.Username,
|
||||||
|
RouteNames: service.AllService.UserService.RouteNames(u),
|
||||||
|
Nickname: u.Nickname,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -59,6 +59,59 @@ func (o *Oauth) OidcAuth(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *Oauth) OidcAuthQueryPre(c *gin.Context) (*model.User, *model.UserToken) {
|
||||||
|
var u *model.User
|
||||||
|
var ut *model.UserToken
|
||||||
|
q := &api.OidcAuthQuery{}
|
||||||
|
|
||||||
|
// 解析查询参数并处理错误
|
||||||
|
if err := c.ShouldBindQuery(q); err != nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "ParamsError")+": "+err.Error())
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取 OAuth 缓存
|
||||||
|
v := service.AllService.OauthService.GetOauthCache(q.Code)
|
||||||
|
if v == nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "OauthExpired"))
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果 UserId 为 0,说明还在授权中
|
||||||
|
if v.UserId == 0 {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"message": "Authorization in progress"})
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户信息
|
||||||
|
u = service.AllService.UserService.InfoById(v.UserId)
|
||||||
|
if u == nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "UserNotFound"))
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除 OAuth 缓存
|
||||||
|
service.AllService.OauthService.DeleteOauthCache(q.Code)
|
||||||
|
|
||||||
|
// 创建登录日志并生成用户令牌
|
||||||
|
ut = service.AllService.UserService.Login(u, &model.LoginLog{
|
||||||
|
UserId: u.Id,
|
||||||
|
Client: v.DeviceType,
|
||||||
|
Uuid: v.Uuid,
|
||||||
|
Ip: c.ClientIP(),
|
||||||
|
Type: model.LoginLogTypeOauth,
|
||||||
|
Platform: v.DeviceOs,
|
||||||
|
})
|
||||||
|
|
||||||
|
if ut == nil {
|
||||||
|
response.Error(c, response.TranslateMsg(c, "LoginFailed"))
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回用户令牌
|
||||||
|
return u, ut
|
||||||
|
}
|
||||||
|
|
||||||
// OidcAuthQuery
|
// OidcAuthQuery
|
||||||
// @Tags Oauth
|
// @Tags Oauth
|
||||||
// @Summary OidcAuthQuery
|
// @Summary OidcAuthQuery
|
||||||
@@ -69,33 +122,7 @@ func (o *Oauth) OidcAuth(c *gin.Context) {
|
|||||||
// @Failure 500 {object} response.ErrorResponse
|
// @Failure 500 {object} response.ErrorResponse
|
||||||
// @Router /oidc/auth-query [get]
|
// @Router /oidc/auth-query [get]
|
||||||
func (o *Oauth) OidcAuthQuery(c *gin.Context) {
|
func (o *Oauth) OidcAuthQuery(c *gin.Context) {
|
||||||
q := &api.OidcAuthQuery{}
|
u, ut := o.OidcAuthQueryPre(c)
|
||||||
err := c.ShouldBindQuery(q)
|
|
||||||
if err != nil {
|
|
||||||
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
v := service.AllService.OauthService.GetOauthCache(q.Code)
|
|
||||||
if v == nil {
|
|
||||||
response.Error(c, response.TranslateMsg(c, "OauthExpired"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if v.UserId == 0 {
|
|
||||||
//正在授权
|
|
||||||
c.JSON(http.StatusOK, gin.H{})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
u := service.AllService.UserService.InfoById(v.UserId)
|
|
||||||
//fmt.Println("auth success u", u)
|
|
||||||
service.AllService.OauthService.DeleteOauthCache(q.Code)
|
|
||||||
ut := service.AllService.UserService.Login(u, &model.LoginLog{
|
|
||||||
UserId: u.Id,
|
|
||||||
Client: v.DeviceType,
|
|
||||||
Uuid: v.Uuid,
|
|
||||||
Ip: c.ClientIP(),
|
|
||||||
Type: model.LoginLogTypeOauth,
|
|
||||||
Platform: v.DeviceOs,
|
|
||||||
})
|
|
||||||
c.JSON(http.StatusOK, apiResp.LoginRes{
|
c.JSON(http.StatusOK, apiResp.LoginRes{
|
||||||
AccessToken: ut.Token,
|
AccessToken: ut.Token,
|
||||||
Type: "access_token",
|
Type: "access_token",
|
||||||
@@ -129,6 +156,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
|||||||
|
|
||||||
ty := v.Op
|
ty := v.Op
|
||||||
ac := v.Action
|
ac := v.Action
|
||||||
|
var u *model.User
|
||||||
//fmt.Println("ty ac ", ty, ac)
|
//fmt.Println("ty ac ", ty, ac)
|
||||||
if ty == model.OauthTypeGithub {
|
if ty == model.OauthTypeGithub {
|
||||||
code := c.Query("code")
|
code := c.Query("code")
|
||||||
@@ -145,7 +173,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
//绑定
|
//绑定
|
||||||
u := service.AllService.UserService.InfoById(v.UserId)
|
u = service.AllService.UserService.InfoById(v.UserId)
|
||||||
if u == nil {
|
if u == nil {
|
||||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound"))
|
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
return
|
return
|
||||||
@@ -164,7 +192,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
|||||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess"))
|
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
u := service.AllService.UserService.InfoByGithubId(strconv.Itoa(userData.Id))
|
u = service.AllService.UserService.InfoByGithubId(strconv.Itoa(userData.Id))
|
||||||
if u == nil {
|
if u == nil {
|
||||||
oa := service.AllService.OauthService.InfoByOp(ty)
|
oa := service.AllService.OauthService.InfoByOp(ty)
|
||||||
if !*oa.AutoRegister {
|
if !*oa.AutoRegister {
|
||||||
@@ -184,15 +212,13 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
v.UserId = u.Id
|
// v.UserId = u.Id
|
||||||
service.AllService.OauthService.SetOauthCache(cacheKey, v, 0)
|
// service.AllService.OauthService.SetOauthCache(cacheKey, v, 0)
|
||||||
c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess"))
|
// c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess"))
|
||||||
return
|
// return
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} else if ty == model.OauthTypeGoogle {
|
||||||
|
|
||||||
if ty == model.OauthTypeGoogle {
|
|
||||||
code := c.Query("code")
|
code := c.Query("code")
|
||||||
err, userData := service.AllService.OauthService.GoogleCallback(code)
|
err, userData := service.AllService.OauthService.GoogleCallback(code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -209,7 +235,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
//绑定
|
//绑定
|
||||||
u := service.AllService.UserService.InfoById(v.UserId)
|
u = service.AllService.UserService.InfoById(v.UserId)
|
||||||
if u == nil {
|
if u == nil {
|
||||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound"))
|
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
return
|
return
|
||||||
@@ -227,7 +253,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
|||||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess"))
|
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
u := service.AllService.UserService.InfoByGoogleEmail(userData.Email)
|
u = service.AllService.UserService.InfoByGoogleEmail(userData.Email)
|
||||||
if u == nil {
|
if u == nil {
|
||||||
oa := service.AllService.OauthService.InfoByOp(ty)
|
oa := service.AllService.OauthService.InfoByOp(ty)
|
||||||
if !*oa.AutoRegister {
|
if !*oa.AutoRegister {
|
||||||
@@ -248,13 +274,12 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
v.UserId = u.Id
|
// v.UserId = u.Id
|
||||||
service.AllService.OauthService.SetOauthCache(cacheKey, v, 0)
|
// service.AllService.OauthService.SetOauthCache(cacheKey, v, 0)
|
||||||
c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess"))
|
// c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess"))
|
||||||
return
|
// return
|
||||||
}
|
}
|
||||||
}
|
} else if ty == model.OauthTypeOidc {
|
||||||
if ty == model.OauthTypeOidc {
|
|
||||||
code := c.Query("code")
|
code := c.Query("code")
|
||||||
err, userData := service.AllService.OauthService.OidcCallback(code)
|
err, userData := service.AllService.OauthService.OidcCallback(code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -271,7 +296,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
//绑定
|
//绑定
|
||||||
u := service.AllService.UserService.InfoById(v.UserId)
|
u = service.AllService.UserService.InfoById(v.UserId)
|
||||||
if u == nil {
|
if u == nil {
|
||||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound"))
|
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound"))
|
||||||
return
|
return
|
||||||
@@ -289,7 +314,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
|||||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess"))
|
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
u := service.AllService.UserService.InfoByOidcSub(userData.Sub)
|
u = service.AllService.UserService.InfoByOidcSub(userData.Sub)
|
||||||
if u == nil {
|
if u == nil {
|
||||||
oa := service.AllService.OauthService.InfoByOp(ty)
|
oa := service.AllService.OauthService.InfoByOp(ty)
|
||||||
if !*oa.AutoRegister {
|
if !*oa.AutoRegister {
|
||||||
@@ -311,13 +336,35 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
v.UserId = u.Id
|
// v.UserId = u.Id
|
||||||
service.AllService.OauthService.SetOauthCache(cacheKey, v, 0)
|
// service.AllService.OauthService.SetOauthCache(cacheKey, v, 0)
|
||||||
c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess"))
|
// c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess"))
|
||||||
|
// return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果u为空,说明没有绑定用户
|
||||||
|
if u == nil {
|
||||||
|
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "SystemError"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// 认证成功,设置缓存
|
||||||
|
v.UserId = u.Id
|
||||||
|
service.AllService.OauthService.SetOauthCache(cacheKey, v, 0)
|
||||||
|
// 如果是webadmin,登录成功后跳转到webadmin
|
||||||
|
if v.DeviceType == "webadmin" {
|
||||||
|
service.AllService.UserService.Login(u, &model.LoginLog{
|
||||||
|
UserId: u.Id,
|
||||||
|
Client: "webadmin",
|
||||||
|
Uuid: "",//must be empty
|
||||||
|
Ip: c.ClientIP(),
|
||||||
|
Type: "account",
|
||||||
|
Platform: v.DeviceOs,
|
||||||
|
})
|
||||||
|
url := global.Config.Rustdesk.ApiServer + "/_admin/#/"
|
||||||
|
c.Redirect(http.StatusFound, url)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess"))
|
||||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "SystemError"))
|
return
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ func Init(g *gin.Engine) {
|
|||||||
rs := &admin.Rustdesk{}
|
rs := &admin.Rustdesk{}
|
||||||
adg.GET("/server-config", rs.ServerConfig)
|
adg.GET("/server-config", rs.ServerConfig)
|
||||||
adg.GET("/app-config", rs.AppConfig)
|
adg.GET("/app-config", rs.AppConfig)
|
||||||
|
|
||||||
//访问静态文件
|
//访问静态文件
|
||||||
//g.StaticFS("/upload", http.Dir(global.Config.Gin.ResourcesPath+"/upload"))
|
//g.StaticFS("/upload", http.Dir(global.Config.Gin.ResourcesPath+"/upload"))
|
||||||
}
|
}
|
||||||
@@ -41,6 +40,9 @@ func LoginBind(rg *gin.RouterGroup) {
|
|||||||
cont := &admin.Login{}
|
cont := &admin.Login{}
|
||||||
rg.POST("/login", cont.Login)
|
rg.POST("/login", cont.Login)
|
||||||
rg.POST("/logout", cont.Logout)
|
rg.POST("/logout", cont.Logout)
|
||||||
|
rg.GET("/login-options", cont.LoginOptions)
|
||||||
|
rg.POST("/oidc/auth", cont.OidcAuth)
|
||||||
|
rg.GET("/oidc/auth-query", cont.OidcAuthQuery)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UserBind(rg *gin.RouterGroup) {
|
func UserBind(rg *gin.RouterGroup) {
|
||||||
|
|||||||
Reference in New Issue
Block a user