mirror of https://github.com/cloudreve/Cloudreve
Feat experimental WebAuth API
parent
0932a10fed
commit
f35c585edf
1
go.mod
1
go.mod
|
@ -4,6 +4,7 @@ go 1.12
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/DATA-DOG/go-sqlmock v1.3.3
|
github.com/DATA-DOG/go-sqlmock v1.3.3
|
||||||
|
github.com/duo-labs/webauthn v0.0.0-20191119193225-4bf9a0f776d4
|
||||||
github.com/fatih/color v1.7.0
|
github.com/fatih/color v1.7.0
|
||||||
github.com/garyburd/redigo v1.6.0
|
github.com/garyburd/redigo v1.6.0
|
||||||
github.com/gin-contrib/cors v1.3.0
|
github.com/gin-contrib/cors v1.3.0
|
||||||
|
|
3
main.go
3
main.go
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/HFO4/cloudreve/models"
|
"github.com/HFO4/cloudreve/models"
|
||||||
|
"github.com/HFO4/cloudreve/pkg/authn"
|
||||||
"github.com/HFO4/cloudreve/pkg/conf"
|
"github.com/HFO4/cloudreve/pkg/conf"
|
||||||
"github.com/HFO4/cloudreve/routers"
|
"github.com/HFO4/cloudreve/routers"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
@ -19,6 +20,8 @@ func init() {
|
||||||
if !conf.SystemConfig.Debug {
|
if !conf.SystemConfig.Debug {
|
||||||
gin.SetMode(gin.ReleaseMode)
|
gin.SetMode(gin.ReleaseMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
authn.Init()
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -2,9 +2,12 @@ package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"github.com/HFO4/cloudreve/pkg/util"
|
"github.com/HFO4/cloudreve/pkg/util"
|
||||||
|
"github.com/duo-labs/webauthn/webauthn"
|
||||||
"github.com/jinzhu/gorm"
|
"github.com/jinzhu/gorm"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -38,6 +41,7 @@ type User struct {
|
||||||
Delay int
|
Delay int
|
||||||
Avatar string
|
Avatar string
|
||||||
Options string `json:"-",gorm:"size:4096"`
|
Options string `json:"-",gorm:"size:4096"`
|
||||||
|
Authn string `gorm:"size:8192"`
|
||||||
|
|
||||||
// 关联模型
|
// 关联模型
|
||||||
Group Group `gorm:"association_autoupdate:false"`
|
Group Group `gorm:"association_autoupdate:false"`
|
||||||
|
@ -55,6 +59,41 @@ type UserOption struct {
|
||||||
PreferredTheme string `json:"preferred_theme"`
|
PreferredTheme string `json:"preferred_theme"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (user User) WebAuthnID() []byte {
|
||||||
|
bs := make([]byte, 8)
|
||||||
|
binary.LittleEndian.PutUint64(bs, uint64(user.ID))
|
||||||
|
return bs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user User) WebAuthnName() string {
|
||||||
|
return user.Email
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user User) WebAuthnDisplayName() string {
|
||||||
|
return user.Nick
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user User) WebAuthnIcon() string {
|
||||||
|
return "https://cdn4.buysellads.net/uu/1/46074/1559075156-slack-carbon-red_2x.png"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user User) WebAuthnCredentials() []webauthn.Credential {
|
||||||
|
var res []webauthn.Credential
|
||||||
|
err := json.Unmarshal([]byte(user.Authn), &res)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user *User) RegisterAuthn(credential *webauthn.Credential) {
|
||||||
|
res, err := json.Marshal([]webauthn.Credential{*credential})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
DB.Model(user).UpdateColumn("authn", string(res))
|
||||||
|
}
|
||||||
|
|
||||||
// Root 获取用户的根目录
|
// Root 获取用户的根目录
|
||||||
func (user *User) Root() (*Folder, error) {
|
func (user *User) Root() (*Folder, error) {
|
||||||
var folder Folder
|
var folder Folder
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package authn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duo-labs/webauthn/webauthn"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Authn *webauthn.WebAuthn
|
||||||
|
|
||||||
|
func Init() {
|
||||||
|
var err error
|
||||||
|
Authn, err = webauthn.New(&webauthn.Config{
|
||||||
|
RPDisplayName: "Duo Labs", // Display Name for your site
|
||||||
|
RPID: "localhost", // Generally the FQDN for your site
|
||||||
|
RPOrigin: "http://localhost:3000", // The origin URL for WebAuthn requests
|
||||||
|
RPIcon: "https://duo.com/logo.png", // Optional icon URL for your site
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/HFO4/cloudreve/models"
|
"github.com/HFO4/cloudreve/models"
|
||||||
"github.com/HFO4/cloudreve/pkg/filesystem/local"
|
"github.com/HFO4/cloudreve/pkg/filesystem/local"
|
||||||
|
"github.com/HFO4/cloudreve/pkg/filesystem/response"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
@ -27,6 +28,8 @@ type Handler interface {
|
||||||
Delete(ctx context.Context, files []string) ([]string, error)
|
Delete(ctx context.Context, files []string) ([]string, error)
|
||||||
// 获取文件
|
// 获取文件
|
||||||
Get(ctx context.Context, path string) (io.ReadSeeker, error)
|
Get(ctx context.Context, path string) (io.ReadSeeker, error)
|
||||||
|
// 获取缩略图
|
||||||
|
Thumb(ctx context.Context, path string) (*response.ContentResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileSystem 管理文件的文件系统
|
// FileSystem 管理文件的文件系统
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
model "github.com/HFO4/cloudreve/models"
|
model "github.com/HFO4/cloudreve/models"
|
||||||
|
"github.com/HFO4/cloudreve/pkg/filesystem/response"
|
||||||
"github.com/HFO4/cloudreve/pkg/thumb"
|
"github.com/HFO4/cloudreve/pkg/thumb"
|
||||||
"github.com/HFO4/cloudreve/pkg/util"
|
"github.com/HFO4/cloudreve/pkg/util"
|
||||||
)
|
)
|
||||||
|
@ -16,6 +17,24 @@ import (
|
||||||
// HandledExtension 可以生成缩略图的文件扩展名
|
// HandledExtension 可以生成缩略图的文件扩展名
|
||||||
var HandledExtension = []string{"jpg", "jpeg", "png", "gif"}
|
var HandledExtension = []string{"jpg", "jpeg", "png", "gif"}
|
||||||
|
|
||||||
|
// GetThumb 获取文件的缩略图
|
||||||
|
func (fs *FileSystem) GetThumb(ctx context.Context, id uint) (*response.ContentResponse, error) {
|
||||||
|
// 根据 ID 查找文件
|
||||||
|
file, err := model.GetFilesByIDs([]uint{id}, fs.User.ID)
|
||||||
|
if err != nil || len(file) == 0 || file[0].PicInfo == "" {
|
||||||
|
return &response.ContentResponse{
|
||||||
|
Redirect: false,
|
||||||
|
}, ErrObjectNotExist
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.FileTarget = []model.File{file[0]}
|
||||||
|
|
||||||
|
res, err := fs.Handler.Thumb(ctx, file[0].SourceName)
|
||||||
|
|
||||||
|
// TODO 出错时重新生成缩略图
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
// GenerateThumbnail 尝试为本地策略文件生成缩略图并获取图像原始大小
|
// GenerateThumbnail 尝试为本地策略文件生成缩略图并获取图像原始大小
|
||||||
func (fs *FileSystem) GenerateThumbnail(ctx context.Context, file *model.File) {
|
func (fs *FileSystem) GenerateThumbnail(ctx context.Context, file *model.File) {
|
||||||
// 判断是否可以生成缩略图
|
// 判断是否可以生成缩略图
|
||||||
|
@ -61,6 +80,7 @@ func (fs *FileSystem) GenerateThumbnail(ctx context.Context, file *model.File) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateThumbnailSize 获取要生成的缩略图的尺寸
|
// GenerateThumbnailSize 获取要生成的缩略图的尺寸
|
||||||
|
// TODO 从配置文件读取
|
||||||
func (fs *FileSystem) GenerateThumbnailSize(w, h int) (uint, uint) {
|
func (fs *FileSystem) GenerateThumbnailSize(w, h int) (uint, uint) {
|
||||||
return 230, 200
|
return 400, 300
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/HFO4/cloudreve/pkg/filesystem/response"
|
||||||
"github.com/HFO4/cloudreve/pkg/util"
|
"github.com/HFO4/cloudreve/pkg/util"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
@ -82,3 +83,16 @@ func (handler Handler) Delete(ctx context.Context, files []string) ([]string, er
|
||||||
|
|
||||||
return deleteFailed, retErr
|
return deleteFailed, retErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Thumb 获取文件缩略图
|
||||||
|
func (handler Handler) Thumb(ctx context.Context, path string) (*response.ContentResponse, error) {
|
||||||
|
file, err := handler.Get(ctx, path+"._thumb")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &response.ContentResponse{
|
||||||
|
Redirect: false,
|
||||||
|
Content: file,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package response
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
// ContentResponse 获取文件内容类方法的通用返回值。
|
||||||
|
// 有些上传策略需要重定向,
|
||||||
|
// 有些直接写文件数据到浏览器
|
||||||
|
type ContentResponse struct {
|
||||||
|
Redirect bool
|
||||||
|
Content io.ReadSeeker
|
||||||
|
URL string
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
model "github.com/HFO4/cloudreve/models"
|
model "github.com/HFO4/cloudreve/models"
|
||||||
"github.com/HFO4/cloudreve/pkg/filesystem/local"
|
"github.com/HFO4/cloudreve/pkg/filesystem/local"
|
||||||
|
"github.com/HFO4/cloudreve/pkg/filesystem/response"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/jinzhu/gorm"
|
"github.com/jinzhu/gorm"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -34,6 +35,11 @@ func (m FileHeaderMock) Delete(ctx context.Context, files []string) ([]string, e
|
||||||
return args.Get(0).([]string), args.Error(1)
|
return args.Get(0).([]string), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m FileHeaderMock) Thumb(ctx context.Context, files string) (*response.ContentResponse, error) {
|
||||||
|
args := m.Called(ctx, files)
|
||||||
|
return args.Get(0).(*response.ContentResponse), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
func TestFileSystem_Upload(t *testing.T) {
|
func TestFileSystem_Upload(t *testing.T) {
|
||||||
asserts := assert.New(t)
|
asserts := assert.New(t)
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ func (image *Thumb) Save(path string) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = jpeg.Encode(out, image.src, nil)
|
err = png.Encode(out, image.src)
|
||||||
return err
|
return err
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
|
import "C"
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/HFO4/cloudreve/models"
|
"github.com/HFO4/cloudreve/models"
|
||||||
|
@ -9,10 +10,45 @@ import (
|
||||||
"github.com/HFO4/cloudreve/pkg/util"
|
"github.com/HFO4/cloudreve/pkg/util"
|
||||||
"github.com/HFO4/cloudreve/service/explorer"
|
"github.com/HFO4/cloudreve/service/explorer"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Thumb 获取文件缩略图
|
||||||
|
func Thumb(c *gin.Context) {
|
||||||
|
// 创建上下文
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
fs, err := filesystem.NewFileSystemFromContext(c)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(200, serializer.Err(serializer.CodePolicyNotAllowed, err.Error(), err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取文件ID
|
||||||
|
fileID, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(200, serializer.ParamErr("无法解析文件ID", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取缩略图
|
||||||
|
resp, err := fs.GetThumb(ctx, uint(fileID))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(200, serializer.Err(serializer.CodeNotSet, "无法获取缩略图", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Redirect {
|
||||||
|
c.Redirect(http.StatusMovedPermanently, resp.URL)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
http.ServeContent(c.Writer, c.Request, "thumb.png", fs.FileTarget[0].UpdatedAt, resp.Content)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Download 文件下载
|
// Download 文件下载
|
||||||
func Download(c *gin.Context) {
|
func Download(c *gin.Context) {
|
||||||
// 创建上下文
|
// 创建上下文
|
||||||
|
|
|
@ -1,11 +1,109 @@
|
||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
model "github.com/HFO4/cloudreve/models"
|
||||||
|
"github.com/HFO4/cloudreve/pkg/authn"
|
||||||
"github.com/HFO4/cloudreve/pkg/serializer"
|
"github.com/HFO4/cloudreve/pkg/serializer"
|
||||||
|
"github.com/HFO4/cloudreve/pkg/util"
|
||||||
"github.com/HFO4/cloudreve/service/user"
|
"github.com/HFO4/cloudreve/service/user"
|
||||||
|
"github.com/duo-labs/webauthn/webauthn"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// StartLoginAuthn 开始注册WebAuthn登录
|
||||||
|
func StartLoginAuthn(c *gin.Context) {
|
||||||
|
userName := c.Param("username")
|
||||||
|
expectedUser, err := model.GetUserByEmail(userName)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(200, serializer.Err(401, "用户邮箱或密码错误", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
options, sessionData, err := authn.Authn.BeginLogin(expectedUser)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(200, ErrorResponse(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val, err := json.Marshal(sessionData)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(200, ErrorResponse(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
util.SetSession(c, map[string]interface{}{
|
||||||
|
"registration-session": val,
|
||||||
|
})
|
||||||
|
c.JSON(200, serializer.Response{Code: 0, Data: options})
|
||||||
|
}
|
||||||
|
|
||||||
|
// FinishLoginAuthn 完成注册WebAuthn登录
|
||||||
|
func FinishLoginAuthn(c *gin.Context) {
|
||||||
|
userName := c.Param("username")
|
||||||
|
expectedUser, err := model.GetUserByEmail(userName)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(200, serializer.Err(401, "用户邮箱或密码错误", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionDataJSON := util.GetSession(c, "registration-session").([]byte)
|
||||||
|
|
||||||
|
var sessionData webauthn.SessionData
|
||||||
|
err = json.Unmarshal(sessionDataJSON, &sessionData)
|
||||||
|
|
||||||
|
_, err = authn.Authn.FinishLogin(expectedUser, sessionData, c.Request)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(200, serializer.Err(401, "用户邮箱或密码错误", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
util.SetSession(c, map[string]interface{}{
|
||||||
|
"user_id": expectedUser.ID,
|
||||||
|
})
|
||||||
|
c.JSON(200, serializer.BuildUserResponse(expectedUser))
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartRegAuthn 开始注册WebAuthn信息
|
||||||
|
func StartRegAuthn(c *gin.Context) {
|
||||||
|
currUser := CurrentUser(c)
|
||||||
|
options, sessionData, err := authn.Authn.BeginRegistration(currUser)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(200, ErrorResponse(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val, err := json.Marshal(sessionData)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(200, ErrorResponse(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
util.SetSession(c, map[string]interface{}{
|
||||||
|
"registration-session": val,
|
||||||
|
})
|
||||||
|
c.JSON(200, serializer.Response{Code: 0, Data: options})
|
||||||
|
}
|
||||||
|
|
||||||
|
// FinishRegAuthn 完成注册WebAuthn信息
|
||||||
|
func FinishRegAuthn(c *gin.Context) {
|
||||||
|
currUser := CurrentUser(c)
|
||||||
|
sessionDataJSON := util.GetSession(c, "registration-session").([]byte)
|
||||||
|
|
||||||
|
var sessionData webauthn.SessionData
|
||||||
|
err := json.Unmarshal(sessionDataJSON, &sessionData)
|
||||||
|
|
||||||
|
credential, err := authn.Authn.FinishRegistration(currUser, sessionData, c.Request)
|
||||||
|
|
||||||
|
currUser.RegisterAuthn(credential)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(200, ErrorResponse(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(200, serializer.Response{Code: 0})
|
||||||
|
}
|
||||||
|
|
||||||
// UserLogin 用户登录
|
// UserLogin 用户登录
|
||||||
func UserLogin(c *gin.Context) {
|
func UserLogin(c *gin.Context) {
|
||||||
var service user.UserLoginService
|
var service user.UserLoginService
|
||||||
|
|
|
@ -43,6 +43,10 @@ func InitRouter() *gin.Engine {
|
||||||
v3.GET("site/ping", controllers.Ping)
|
v3.GET("site/ping", controllers.Ping)
|
||||||
// 用户登录
|
// 用户登录
|
||||||
v3.POST("user/session", controllers.UserLogin)
|
v3.POST("user/session", controllers.UserLogin)
|
||||||
|
// WebAuthn登陆初始化
|
||||||
|
v3.GET("user/authn/:username", controllers.StartLoginAuthn)
|
||||||
|
// WebAuthn登陆
|
||||||
|
v3.POST("user/authn/finish/:username", controllers.FinishLoginAuthn)
|
||||||
// 验证码
|
// 验证码
|
||||||
v3.GET("captcha", controllers.Captcha)
|
v3.GET("captcha", controllers.Captcha)
|
||||||
// 站点全局配置
|
// 站点全局配置
|
||||||
|
@ -58,6 +62,13 @@ func InitRouter() *gin.Engine {
|
||||||
// 当前登录用户信息
|
// 当前登录用户信息
|
||||||
user.GET("me", controllers.UserMe)
|
user.GET("me", controllers.UserMe)
|
||||||
user.GET("storage", controllers.UserStorage)
|
user.GET("storage", controllers.UserStorage)
|
||||||
|
|
||||||
|
// WebAuthn 注册相关
|
||||||
|
authn := user.Group("authn")
|
||||||
|
{
|
||||||
|
authn.PUT("", controllers.StartRegAuthn)
|
||||||
|
authn.PUT("finish", controllers.FinishRegAuthn)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 文件
|
// 文件
|
||||||
|
@ -66,7 +77,9 @@ func InitRouter() *gin.Engine {
|
||||||
// 文件上传
|
// 文件上传
|
||||||
file.POST("upload", controllers.FileUploadStream)
|
file.POST("upload", controllers.FileUploadStream)
|
||||||
// 下载文件
|
// 下载文件
|
||||||
file.GET("*path", controllers.Download)
|
file.GET("download/*path", controllers.Download)
|
||||||
|
// 下载文件
|
||||||
|
file.GET("thumb/:id", controllers.Thumb)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 目录
|
// 目录
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package user
|
package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/HFO4/cloudreve/models"
|
"github.com/HFO4/cloudreve/models"
|
||||||
"github.com/HFO4/cloudreve/pkg/serializer"
|
"github.com/HFO4/cloudreve/pkg/serializer"
|
||||||
"github.com/HFO4/cloudreve/pkg/util"
|
"github.com/HFO4/cloudreve/pkg/util"
|
||||||
|
@ -53,8 +52,6 @@ func (service *UserLoginService) Login(c *gin.Context) serializer.Response {
|
||||||
"user_id": expectedUser.ID,
|
"user_id": expectedUser.ID,
|
||||||
})
|
})
|
||||||
|
|
||||||
fmt.Println(expectedUser)
|
|
||||||
|
|
||||||
return serializer.BuildUserResponse(expectedUser)
|
return serializer.BuildUserResponse(expectedUser)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue