Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb8a936ade | ||
|
|
61044fd30b | ||
|
|
22a4546d0f | ||
|
|
07450416ed | ||
|
|
0d6db0d2a1 | ||
|
|
ab30b3407b | ||
|
|
7a4c735803 | ||
|
|
654c764019 | ||
|
|
7101139250 | ||
|
|
793614841a |
271
.github/workflows/build_test.yml
vendored
Normal file
271
.github/workflows/build_test.yml
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
name: Build Test
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
BASE_IMAGE_NAMESPACE:
|
||||
description: 'Base image namespace (Default: Your Github username)'
|
||||
required: false
|
||||
default: ''
|
||||
DOCKERHUB_IMAGE_NAMESPACE:
|
||||
description: 'Docker Hub image namespace (Default: Your Github username)'
|
||||
required: false
|
||||
default: ''
|
||||
GHCR_IMAGE_NAMESPACE:
|
||||
description: 'GitHub Container Registry image namespace (Default: Your Github username)'
|
||||
required: false
|
||||
default: ''
|
||||
SKIP_DOCKER_HUB:
|
||||
description: 'Set to true to skip pushing to Docker Hub (default: false)'
|
||||
required: false
|
||||
default: 'false'
|
||||
SKIP_GHCR:
|
||||
description: 'Set to true to skip pushing to GHCR (default: false)'
|
||||
required: false
|
||||
default: 'false'
|
||||
WEBCLIENT_SOURCE_LOCATION:
|
||||
description: 'Web Client API Repository'
|
||||
required: true
|
||||
default: 'https://github.com/lejianwen/rustdesk-api-web'
|
||||
|
||||
env:
|
||||
LATEST_TAG: latest
|
||||
WEBCLIENT_SOURCE_LOCATION: ${{ github.event.inputs.WEBCLIENT_SOURCE_LOCATION || 'https://github.com/lejianwen/rustdesk-api-web' }}
|
||||
BASE_IMAGE_NAMESPACE: ${{ github.event.inputs.BASE_IMAGE_NAMESPACE || github.actor }}
|
||||
DOCKERHUB_IMAGE_NAMESPACE: ${{ github.event.inputs.DOCKERHUB_IMAGE_NAMESPACE || github.actor }}
|
||||
GHCR_IMAGE_NAMESPACE: ${{ github.event.inputs.GHCR_IMAGE_NAMESPACE || github.actor }}
|
||||
SKIP_DOCKER_HUB: ${{ github.event.inputs.SKIP_DOCKER_HUB || 'false' }}
|
||||
SKIP_GHCR: ${{ github.event.inputs.SKIP_GHCR || 'false' }}
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
- { platform: "amd64", goos: "linux", file_ext: "tar.gz" }
|
||||
- { platform: "arm64", goos: "linux", file_ext: "tar.gz" }
|
||||
- { platform: "armv7l", goos: "linux", file_ext: "tar.gz" }
|
||||
- { platform: "amd64", goos: "windows", file_ext: "zip" }
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go environment
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.22' # 选择 Go 版本
|
||||
|
||||
- name: Set up npm
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
|
||||
- name: build rustdesk-api-web
|
||||
run: |
|
||||
git clone ${{ env.WEBCLIENT_SOURCE_LOCATION }}
|
||||
cd rustdesk-api-web
|
||||
npm install
|
||||
npm run build
|
||||
mkdir ../resources/admin/ -p
|
||||
cp -ar dist/* ../resources/admin/
|
||||
|
||||
- name: tidy
|
||||
run: go mod tidy
|
||||
|
||||
- name: swag
|
||||
run: |
|
||||
go install github.com/swaggo/swag/cmd/swag@latest
|
||||
swag init -g cmd/apimain.go --output docs/api --instanceName api --exclude http/controller/admin
|
||||
swag init -g cmd/apimain.go --output docs/admin --instanceName admin --exclude http/controller/api
|
||||
|
||||
- name: Build for ${{ matrix.job.goos }}-${{ matrix.job.platform }}
|
||||
run: |
|
||||
mkdir release -p
|
||||
cp -ar resources release/
|
||||
cp -ar docs release/
|
||||
cp -ar conf release/
|
||||
mkdir -p release/data
|
||||
mkdir -p release/runtime
|
||||
if [ "${{ matrix.job.goos }}" = "windows" ]; then
|
||||
sudo apt-get install gcc-mingw-w64-x86-64 zip -y
|
||||
GOOS=${{ matrix.job.goos }} GOARCH=${{ matrix.job.platform }} CC=x86_64-w64-mingw32-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain.exe ./cmd/apimain.go
|
||||
zip -r ${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}} ./release
|
||||
else
|
||||
if [ "${{ matrix.job.platform }}" = "arm64" ]; then
|
||||
wget https://musl.cc/aarch64-linux-musl-cross.tgz
|
||||
tar -xf aarch64-linux-musl-cross.tgz
|
||||
export PATH=$PATH:$PWD/aarch64-linux-musl-cross/bin
|
||||
GOOS=${{ matrix.job.goos }} GOARCH=${{ matrix.job.platform }} CC=aarch64-linux-musl-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain ./cmd/apimain.go
|
||||
elif [ "${{ matrix.job.platform }}" = "armv7l" ]; then
|
||||
wget https://musl.cc/armv7l-linux-musleabihf-cross.tgz
|
||||
tar -xf armv7l-linux-musleabihf-cross.tgz
|
||||
export PATH=$PATH:$PWD/armv7l-linux-musleabihf-cross/bin
|
||||
GOOS=${{ matrix.job.goos }} GOARCH=arm GOARM=7 CC=armv7l-linux-musleabihf-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain ./cmd/apimain.go
|
||||
else
|
||||
sudo apt-get install musl musl-dev musl-tools -y
|
||||
GOOS=${{ matrix.job.goos }} GOARCH=${{ matrix.job.platform }} CC=musl-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain ./cmd/apimain.go
|
||||
fi
|
||||
tar -czf ${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}} ./release
|
||||
fi
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: rustdesk-api-${{ matrix.job.goos }}-${{ matrix.job.platform }}
|
||||
path: |
|
||||
${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}}
|
||||
- name: Upload to GitHub Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: |
|
||||
${{ matrix.job.goos}}-${{ matrix.job.platform }}.${{matrix.job.file_ext}}
|
||||
tag_name: test
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
docker:
|
||||
name: Push Docker Image
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
- { platform: "amd64", goos: "linux", docker_platform: "linux/amd64" }
|
||||
- { platform: "arm64", goos: "linux", docker_platform: "linux/arm64" }
|
||||
- { platform: "armv7l", goos: "linux", docker_platform: "linux/arm/v7" }
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
if: ${{ env.SKIP_DOCKER_HUB == 'false' }} # Only log in if SKIP_DOCKER_HUB is false
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
if: ${{ env.SKIP_GHCR == 'false' }} # Only log in if GHCR push is enabled
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract version from tag
|
||||
id: vars
|
||||
run: |
|
||||
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
|
||||
echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
||||
else
|
||||
echo "TAG=test" >> $GITHUB_ENV # Default to 'test' if not a tag
|
||||
fi
|
||||
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api
|
||||
|
||||
- name: Download binaries
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: rustdesk-api-${{ matrix.job.goos }}-${{ matrix.job.platform }}
|
||||
path: ./
|
||||
|
||||
- name: Unzip binaries
|
||||
run: |
|
||||
mkdir -p ${{ matrix.job.platform }}
|
||||
tar -xzf ${{ matrix.job.goos }}-${{ matrix.job.platform }}.tar.gz -C ${{ matrix.job.platform }}
|
||||
file ${{ matrix.job.platform }}/apimain
|
||||
|
||||
- name: Build and push Docker image to Docker Hub ${{ matrix.job.platform }}
|
||||
if: ${{ env.SKIP_DOCKER_HUB == 'false' }} # Only run this step if SKIP_DOCKER_HUB is false
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: "."
|
||||
file: ./Dockerfile
|
||||
platforms: ${{ matrix.job.docker_platform }}
|
||||
push: true
|
||||
provenance: false
|
||||
build-args: |
|
||||
BUILDARCH=${{ matrix.job.platform }}
|
||||
tags: |
|
||||
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-${{ matrix.job.platform }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
- name: Build and push Docker image to GHCR ${{ matrix.job.platform }}
|
||||
if: ${{ env.SKIP_GHCR == 'false' }} # Only run this step if SKIP_GHCR is false
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: "."
|
||||
file: ./Dockerfile
|
||||
platforms: ${{ matrix.job.docker_platform }}
|
||||
push: true
|
||||
provenance: false
|
||||
build-args: |
|
||||
BUILDARCH=${{ matrix.job.platform }}
|
||||
tags: |
|
||||
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-${{ matrix.job.platform }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
#
|
||||
docker-manifest:
|
||||
name: Push Docker Manifest
|
||||
needs: docker
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Extract version from tag
|
||||
id: vars
|
||||
run: |
|
||||
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
|
||||
echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
||||
else
|
||||
echo "TAG=test" >> $GITHUB_ENV # Default to 'test' if not a tag
|
||||
fi
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
if: ${{ env.SKIP_DOCKER_HUB == 'false' }} # Only log in if Docker Hub push is enabled
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
if: ${{ env.SKIP_GHCR == 'false' }} # Only log in if GHCR push is enabled
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Create and push manifest Docker Hub (:version)
|
||||
if: ${{ env.SKIP_DOCKER_HUB == 'false' }}
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
with:
|
||||
base-image: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}
|
||||
extra-images: ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-amd64,
|
||||
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-armv7l,
|
||||
${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-arm64
|
||||
push: true
|
||||
|
||||
- name: Create and push manifest GHCR (:version)
|
||||
if: ${{ env.SKIP_GHCR == 'false' }}
|
||||
uses: Noelware/docker-manifest-action@master
|
||||
with:
|
||||
base-image: ghcr.io/${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}
|
||||
extra-images: ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-amd64,
|
||||
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-armv7l,
|
||||
ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-arm64
|
||||
push: true
|
||||
amend: true
|
||||
95
.github/workflows/release.yml
vendored
95
.github/workflows/release.yml
vendored
@@ -1,95 +0,0 @@
|
||||
name: Build and Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
# tags:
|
||||
# - 'v*.*.*' # 当推送带有版本号的 tag(例如 v1.0.0)时触发工作流
|
||||
#on:
|
||||
# push:
|
||||
# branches: [ "master" ]
|
||||
# pull_request:
|
||||
# branches: [ "master" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
goos: [ linux, windows ] # 指定要构建的操作系统
|
||||
goarch: [ amd64 ] # 指定架构
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go environment
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.22' # 选择 Go 版本
|
||||
|
||||
- name: Set up npm
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: install gcc zip musl
|
||||
run: |
|
||||
if [ "${{ matrix.goos }}" = "windows" ]; then
|
||||
sudo apt-get install gcc-mingw-w64-x86-64 zip -y
|
||||
else
|
||||
sudo apt-get install musl musl-dev musl-tools -y
|
||||
fi
|
||||
|
||||
|
||||
- name: build rustdesk-api-web
|
||||
run: |
|
||||
git clone https://github.com/lejianwen/rustdesk-api-web
|
||||
cd rustdesk-api-web
|
||||
npm install
|
||||
npm run build
|
||||
mkdir ../resources/admin/ -p
|
||||
cp -ar dist/* ../resources/admin/
|
||||
|
||||
- name: tidy
|
||||
run: go mod tidy
|
||||
|
||||
|
||||
- name: swag
|
||||
run: |
|
||||
go install github.com/swaggo/swag/cmd/swag@latest
|
||||
swag init -g cmd/apimain.go --output docs/api --instanceName api --exclude http/controller/admin
|
||||
swag init -g cmd/apimain.go --output docs/admin --instanceName admin --exclude http/controller/api
|
||||
|
||||
- name: Build for ${{ matrix.goos }}-${{ matrix.goarch }}
|
||||
run: |
|
||||
mkdir release -p
|
||||
cp -ar resources release/
|
||||
cp -ar docs release/
|
||||
cp -ar conf release/
|
||||
mkdir -p release/data
|
||||
mkdir -p release/runtime
|
||||
if [ "${{ matrix.goos }}" = "windows" ]; then
|
||||
GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} CC=x86_64-w64-mingw32-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain.exe ./cmd/apimain.go
|
||||
zip -r ${{ matrix.goos}}-${{ matrix.goarch }}.zip ./release
|
||||
else
|
||||
GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} CC=musl-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain ./cmd/apimain.go
|
||||
tar -czf ${{ matrix.goos}}-${{ matrix.goarch }}.tar.gz ./release
|
||||
fi
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: myapp-${{ matrix.goos }}-${{ matrix.goarch }}
|
||||
path: |
|
||||
${{ matrix.goos}}-${{ matrix.goarch }}.tar.gz
|
||||
${{ matrix.goos}}-${{ matrix.goarch }}.zip
|
||||
|
||||
- name: Upload to GitHub Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: |
|
||||
${{ matrix.goos}}-${{ matrix.goarch }}.tar.gz
|
||||
${{ matrix.goos}}-${{ matrix.goarch }}.zip
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -14,6 +14,9 @@ import (
|
||||
"fmt"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// @title 管理系统API
|
||||
@@ -26,9 +29,79 @@ import (
|
||||
// @securitydefinitions.apikey BearerAuth
|
||||
// @in header
|
||||
// @name Authorization
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "apimain",
|
||||
Short: "RUSTDESK API SERVER",
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
InitGlobal()
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
//gin
|
||||
http.ApiInit()
|
||||
},
|
||||
}
|
||||
|
||||
var resetPwdCmd = &cobra.Command{
|
||||
Use: "reset-admin-pwd [pwd]",
|
||||
Example: "reset-admin-pwd 123456",
|
||||
Short: "Reset Admin Password",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
pwd := args[0]
|
||||
admin := service.AllService.UserService.InfoById(1)
|
||||
err := service.AllService.UserService.UpdatePassword(admin, pwd)
|
||||
if err != nil {
|
||||
fmt.Printf("reset password fail! %v \n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("reset password success! \n")
|
||||
},
|
||||
}
|
||||
var resetUserPwdCmd = &cobra.Command{
|
||||
Use: "reset-pwd [userId] [pwd]",
|
||||
Example: "reset-pwd 2 123456",
|
||||
Short: "Reset User Password",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
userId := args[0]
|
||||
pwd := args[1]
|
||||
uid, err := strconv.Atoi(userId)
|
||||
if err != nil {
|
||||
fmt.Printf("userId must be int! \n")
|
||||
return
|
||||
}
|
||||
if uid <= 0 {
|
||||
fmt.Printf("userId must be greater than 0! \n")
|
||||
return
|
||||
}
|
||||
u := service.AllService.UserService.InfoById(uint(uid))
|
||||
err = service.AllService.UserService.UpdatePassword(u, pwd)
|
||||
if err != nil {
|
||||
fmt.Printf("reset password fail! %v \n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("reset password success! \n")
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.PersistentFlags().StringVarP(&global.ConfigPath, "config", "c", "./conf/config.yaml", "choose config file")
|
||||
rootCmd.AddCommand(resetPwdCmd, resetUserPwdCmd)
|
||||
}
|
||||
func main() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func InitGlobal() {
|
||||
//配置解析
|
||||
global.Viper = config.Init(&global.Config)
|
||||
global.Viper = config.Init(&global.Config, global.ConfigPath)
|
||||
|
||||
//从配置文件中加载密钥
|
||||
config.LoadKeyFile(&global.Config.Rustdesk)
|
||||
|
||||
//日志
|
||||
global.Logger = logger.New(&logger.Config{
|
||||
@@ -94,14 +167,9 @@ func main() {
|
||||
|
||||
//locker
|
||||
global.Lock = lock.NewLocal()
|
||||
|
||||
//gin
|
||||
http.ApiInit()
|
||||
|
||||
}
|
||||
|
||||
func DatabaseAutoUpdate() {
|
||||
version := 245
|
||||
version := 246
|
||||
|
||||
db := global.DB
|
||||
|
||||
@@ -150,7 +218,7 @@ func DatabaseAutoUpdate() {
|
||||
if v.Version < 245 {
|
||||
//oauths 表的 oauth_type 字段设置为 op同样的值
|
||||
db.Exec("update oauths set oauth_type = op")
|
||||
db.Exec("update oauths set issuer = 'https://accounts.google.com' where op = 'google' and issuer = ''")
|
||||
db.Exec("update oauths set issuer = 'https://accounts.google.com' where op = 'google'")
|
||||
db.Exec("update user_thirds set oauth_type = third_type, op = third_type")
|
||||
//通过email迁移旧的google授权
|
||||
uts := make([]model.UserThird, 0)
|
||||
@@ -161,6 +229,9 @@ func DatabaseAutoUpdate() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if v.Version < 246 {
|
||||
db.Exec("update oauths set issuer = 'https://accounts.google.com' where op = 'google' and issuer is null")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/spf13/viper"
|
||||
@@ -35,18 +34,15 @@ type Config struct {
|
||||
}
|
||||
|
||||
// Init 初始化配置
|
||||
func Init(rowVal interface{}) *viper.Viper {
|
||||
var config string
|
||||
flag.StringVar(&config, "c", "", "choose config file.")
|
||||
flag.Parse()
|
||||
if config == "" { // 优先级: 命令行 > 默认值
|
||||
config = DefaultConfig
|
||||
func Init(rowVal interface{}, path string) *viper.Viper {
|
||||
if path == "" {
|
||||
path = DefaultConfig
|
||||
}
|
||||
v := viper.New()
|
||||
v := viper.GetViper()
|
||||
v.AutomaticEnv()
|
||||
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
|
||||
v.SetEnvPrefix("RUSTDESK_API")
|
||||
v.SetConfigFile(config)
|
||||
v.SetConfigFile(path)
|
||||
v.SetConfigType("yaml")
|
||||
err := v.ReadInConfig()
|
||||
if err != nil {
|
||||
@@ -63,7 +59,7 @@ func Init(rowVal interface{}) *viper.Viper {
|
||||
if err := v.Unmarshal(rowVal); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
LoadKeyFile(&rowVal.(*Config).Rustdesk)
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
|
||||
@@ -3067,6 +3067,90 @@ const docTemplateadmin = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/user/myPeer": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "设备列表",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"设备"
|
||||
],
|
||||
"summary": "设备列表",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "页码",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "页大小",
|
||||
"name": "page_size",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "时间",
|
||||
"name": "time_ago",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "ID",
|
||||
"name": "id",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "主机名",
|
||||
"name": "hostname",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "uuids 用逗号分隔",
|
||||
"name": "uuids",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/response.Response"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/model.PeerList"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/user/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -3407,6 +3491,12 @@ const docTemplateadmin = `{
|
||||
"admin.LoginPayload": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"avatar": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"nickname": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -3429,7 +3519,7 @@ const docTemplateadmin = `{
|
||||
"required": [
|
||||
"client_id",
|
||||
"client_secret",
|
||||
"op",
|
||||
"oauth_type",
|
||||
"redirect_url"
|
||||
],
|
||||
"properties": {
|
||||
@@ -3448,6 +3538,9 @@ const docTemplateadmin = `{
|
||||
"issuer": {
|
||||
"type": "string"
|
||||
},
|
||||
"oauth_type": {
|
||||
"type": "string"
|
||||
},
|
||||
"op": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -3567,6 +3660,10 @@ const docTemplateadmin = `{
|
||||
"avatar": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"description": "validate:\"required,email\" email不强制",
|
||||
"type": "string"
|
||||
},
|
||||
"group_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
@@ -3591,18 +3688,18 @@ const docTemplateadmin = `{
|
||||
"username": {
|
||||
"type": "string",
|
||||
"maxLength": 10,
|
||||
"minLength": 4
|
||||
"minLength": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin.UserOauthItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"op": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"third_type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -3973,6 +4070,9 @@ const docTemplateadmin = `{
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"device_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
@@ -4042,6 +4142,9 @@ const docTemplateadmin = `{
|
||||
"issuer": {
|
||||
"type": "string"
|
||||
},
|
||||
"oauth_type": {
|
||||
"type": "string"
|
||||
},
|
||||
"op": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -4220,6 +4323,9 @@ const docTemplateadmin = `{
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"group_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
@@ -4269,6 +4375,12 @@ const docTemplateadmin = `{
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"device_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"device_uuid": {
|
||||
"type": "string"
|
||||
},
|
||||
"expired_at": {
|
||||
"type": "integer"
|
||||
},
|
||||
|
||||
@@ -3060,6 +3060,90 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/user/myPeer": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"token": []
|
||||
}
|
||||
],
|
||||
"description": "设备列表",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"设备"
|
||||
],
|
||||
"summary": "设备列表",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "页码",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "页大小",
|
||||
"name": "page_size",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "时间",
|
||||
"name": "time_ago",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "ID",
|
||||
"name": "id",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "主机名",
|
||||
"name": "hostname",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "uuids 用逗号分隔",
|
||||
"name": "uuids",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/response.Response"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/model.PeerList"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/user/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -3400,6 +3484,12 @@
|
||||
"admin.LoginPayload": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"avatar": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"nickname": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -3422,7 +3512,7 @@
|
||||
"required": [
|
||||
"client_id",
|
||||
"client_secret",
|
||||
"op",
|
||||
"oauth_type",
|
||||
"redirect_url"
|
||||
],
|
||||
"properties": {
|
||||
@@ -3441,6 +3531,9 @@
|
||||
"issuer": {
|
||||
"type": "string"
|
||||
},
|
||||
"oauth_type": {
|
||||
"type": "string"
|
||||
},
|
||||
"op": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -3560,6 +3653,10 @@
|
||||
"avatar": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"description": "validate:\"required,email\" email不强制",
|
||||
"type": "string"
|
||||
},
|
||||
"group_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
@@ -3584,18 +3681,18 @@
|
||||
"username": {
|
||||
"type": "string",
|
||||
"maxLength": 10,
|
||||
"minLength": 4
|
||||
"minLength": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin.UserOauthItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"op": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"third_type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -3966,6 +4063,9 @@
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"device_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
@@ -4035,6 +4135,9 @@
|
||||
"issuer": {
|
||||
"type": "string"
|
||||
},
|
||||
"oauth_type": {
|
||||
"type": "string"
|
||||
},
|
||||
"op": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -4213,6 +4316,9 @@
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"group_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
@@ -4262,6 +4368,12 @@
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"device_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"device_uuid": {
|
||||
"type": "string"
|
||||
},
|
||||
"expired_at": {
|
||||
"type": "integer"
|
||||
},
|
||||
|
||||
@@ -84,6 +84,10 @@ definitions:
|
||||
type: object
|
||||
admin.LoginPayload:
|
||||
properties:
|
||||
avatar:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
nickname:
|
||||
type: string
|
||||
route_names:
|
||||
@@ -107,6 +111,8 @@ definitions:
|
||||
type: integer
|
||||
issuer:
|
||||
type: string
|
||||
oauth_type:
|
||||
type: string
|
||||
op:
|
||||
type: string
|
||||
redirect_url:
|
||||
@@ -116,7 +122,7 @@ definitions:
|
||||
required:
|
||||
- client_id
|
||||
- client_secret
|
||||
- op
|
||||
- oauth_type
|
||||
- redirect_url
|
||||
type: object
|
||||
admin.PeerBatchDeleteForm:
|
||||
@@ -188,6 +194,9 @@ definitions:
|
||||
properties:
|
||||
avatar:
|
||||
type: string
|
||||
email:
|
||||
description: validate:"required,email" email不强制
|
||||
type: string
|
||||
group_id:
|
||||
type: integer
|
||||
id:
|
||||
@@ -203,7 +212,7 @@ definitions:
|
||||
minimum: 0
|
||||
username:
|
||||
maxLength: 10
|
||||
minLength: 4
|
||||
minLength: 2
|
||||
type: string
|
||||
required:
|
||||
- group_id
|
||||
@@ -212,10 +221,10 @@ definitions:
|
||||
type: object
|
||||
admin.UserOauthItem:
|
||||
properties:
|
||||
op:
|
||||
type: string
|
||||
status:
|
||||
type: integer
|
||||
third_type:
|
||||
type: string
|
||||
type: object
|
||||
admin.UserPasswordForm:
|
||||
properties:
|
||||
@@ -462,6 +471,8 @@ definitions:
|
||||
type: string
|
||||
created_at:
|
||||
type: string
|
||||
device_id:
|
||||
type: string
|
||||
id:
|
||||
type: integer
|
||||
ip:
|
||||
@@ -508,6 +519,8 @@ definitions:
|
||||
type: integer
|
||||
issuer:
|
||||
type: string
|
||||
oauth_type:
|
||||
type: string
|
||||
op:
|
||||
type: string
|
||||
redirect_url:
|
||||
@@ -627,6 +640,8 @@ definitions:
|
||||
type: string
|
||||
created_at:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
group_id:
|
||||
type: integer
|
||||
id:
|
||||
@@ -659,6 +674,10 @@ definitions:
|
||||
properties:
|
||||
created_at:
|
||||
type: string
|
||||
device_id:
|
||||
type: string
|
||||
device_uuid:
|
||||
type: string
|
||||
expired_at:
|
||||
type: integer
|
||||
id:
|
||||
@@ -2519,6 +2538,57 @@ paths:
|
||||
summary: 我的授权
|
||||
tags:
|
||||
- 用户
|
||||
/admin/user/myPeer:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 设备列表
|
||||
parameters:
|
||||
- description: 页码
|
||||
in: query
|
||||
name: page
|
||||
type: integer
|
||||
- description: 页大小
|
||||
in: query
|
||||
name: page_size
|
||||
type: integer
|
||||
- description: 时间
|
||||
in: query
|
||||
name: time_ago
|
||||
type: integer
|
||||
- description: ID
|
||||
in: query
|
||||
name: id
|
||||
type: string
|
||||
- description: 主机名
|
||||
in: query
|
||||
name: hostname
|
||||
type: string
|
||||
- description: uuids 用逗号分隔
|
||||
in: query
|
||||
name: uuids
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/response.Response'
|
||||
- properties:
|
||||
data:
|
||||
$ref: '#/definitions/model.PeerList'
|
||||
type: object
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
security:
|
||||
- token: []
|
||||
summary: 设备列表
|
||||
tags:
|
||||
- 设备
|
||||
/admin/user/update:
|
||||
post:
|
||||
consumes:
|
||||
|
||||
@@ -1365,7 +1365,7 @@ const docTemplateapi = `{
|
||||
"username": {
|
||||
"type": "string",
|
||||
"maxLength": 10,
|
||||
"minLength": 4
|
||||
"minLength": 2
|
||||
},
|
||||
"uuid": {
|
||||
"type": "string"
|
||||
|
||||
@@ -1358,7 +1358,7 @@
|
||||
"username": {
|
||||
"type": "string",
|
||||
"maxLength": 10,
|
||||
"minLength": 4
|
||||
"minLength": 2
|
||||
},
|
||||
"uuid": {
|
||||
"type": "string"
|
||||
|
||||
@@ -69,7 +69,7 @@ definitions:
|
||||
type: string
|
||||
username:
|
||||
maxLength: 10
|
||||
minLength: 4
|
||||
minLength: 2
|
||||
type: string
|
||||
uuid:
|
||||
type: string
|
||||
|
||||
@@ -17,13 +17,14 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
DB *gorm.DB
|
||||
Logger *logrus.Logger
|
||||
Config config.Config
|
||||
Viper *viper.Viper
|
||||
Redis *redis.Client
|
||||
Cache cache.Handler
|
||||
Validator struct {
|
||||
DB *gorm.DB
|
||||
Logger *logrus.Logger
|
||||
ConfigPath string = ""
|
||||
Config config.Config
|
||||
Viper *viper.Viper
|
||||
Redis *redis.Client
|
||||
Cache cache.Handler
|
||||
Validator struct {
|
||||
Validate *validator.Validate
|
||||
UT *ut.UniversalTranslator
|
||||
VTrans ut.Translator
|
||||
|
||||
3
go.mod
3
go.mod
@@ -16,6 +16,7 @@ require (
|
||||
github.com/google/uuid v1.1.2
|
||||
github.com/nicksnyder/go-i18n/v2 v2.4.0
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/viper v1.9.0
|
||||
github.com/swaggo/files v1.0.1
|
||||
github.com/swaggo/gin-swagger v1.6.0
|
||||
@@ -28,7 +29,6 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute/metadata v0.5.1 // indirect
|
||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
@@ -44,6 +44,7 @@ require (
|
||||
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||
github.com/goccy/go-json v0.10.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
|
||||
@@ -17,7 +17,7 @@ func AdminAuth() gin.HandlerFunc {
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
user := service.AllService.UserService.InfoByAccessToken(token)
|
||||
user, ut := service.AllService.UserService.InfoByAccessToken(token)
|
||||
if user.Id == 0 {
|
||||
response.Fail(c, 403, "请先登录")
|
||||
c.Abort()
|
||||
@@ -26,6 +26,8 @@ func AdminAuth() gin.HandlerFunc {
|
||||
|
||||
c.Set("curUser", user)
|
||||
c.Set("token", token)
|
||||
//如果时间小于1天,token自动续期
|
||||
service.AllService.UserService.AutoRefreshAccessToken(ut)
|
||||
|
||||
c.Next()
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ func RustAuth() gin.HandlerFunc {
|
||||
//这里只是简单的提取
|
||||
token = token[7:]
|
||||
//验证token
|
||||
user := service.AllService.UserService.InfoByAccessToken(token)
|
||||
user, ut := service.AllService.UserService.InfoByAccessToken(token)
|
||||
if user.Id == 0 {
|
||||
c.JSON(401, gin.H{
|
||||
"error": "Unauthorized",
|
||||
@@ -46,6 +46,9 @@ func RustAuth() gin.HandlerFunc {
|
||||
|
||||
c.Set("curUser", user)
|
||||
c.Set("token", token)
|
||||
|
||||
service.AllService.UserService.AutoRefreshAccessToken(ut)
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,18 +53,18 @@ func (us *UserService) InfoByUsernamePassword(username, password string) *model.
|
||||
}
|
||||
|
||||
// InfoByAccesstoken 根据accesstoken取用户信息
|
||||
func (us *UserService) InfoByAccessToken(token string) *model.User {
|
||||
func (us *UserService) InfoByAccessToken(token string) (*model.User, *model.UserToken) {
|
||||
u := &model.User{}
|
||||
ut := &model.UserToken{}
|
||||
global.DB.Where("token = ?", token).First(ut)
|
||||
if ut.Id == 0 {
|
||||
return u
|
||||
return u, ut
|
||||
}
|
||||
if ut.ExpiredAt < time.Now().Unix() {
|
||||
return u
|
||||
return u, ut
|
||||
}
|
||||
global.DB.Where("id = ?", ut.UserId).First(u)
|
||||
return u
|
||||
return u, ut
|
||||
}
|
||||
|
||||
// GenerateToken 生成token
|
||||
@@ -215,12 +215,12 @@ func (us *UserService) Delete(u *model.User) error {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
tx.Commit()
|
||||
// 删除关联的peer
|
||||
if err := AllService.PeerService.EraseUserId(u.Id); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
global.Logger.Warn("User deleted successfully, but failed to unlink peer.")
|
||||
return nil
|
||||
}
|
||||
tx.Commit()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -448,3 +448,13 @@ func (us *UserService) getAdminUserCount() int64 {
|
||||
global.DB.Model(&model.User{}).Where("is_admin = ?", true).Count(&count)
|
||||
return count
|
||||
}
|
||||
|
||||
func (us *UserService) RefreshAccessToken(ut *model.UserToken) {
|
||||
ut.ExpiredAt = time.Now().Add(time.Hour * 24 * 7).Unix()
|
||||
global.DB.Model(ut).Update("expired_at", ut.ExpiredAt)
|
||||
}
|
||||
func (us *UserService) AutoRefreshAccessToken(ut *model.UserToken) {
|
||||
if ut.ExpiredAt-time.Now().Unix() < 86400 {
|
||||
us.RefreshAccessToken(ut)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user