Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
hexbee
Cloudreve
提交
7c07b623
C
Cloudreve
项目概览
hexbee
/
Cloudreve
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
C
Cloudreve
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
7c07b623
编写于
2月 21, 2020
作者:
H
HFO4
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Feat: 2-FA login verification
上级
11e45bc7
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
93 addition
and
1 deletion
+93
-1
models/user.go
models/user.go
+7
-0
pkg/serializer/user.go
pkg/serializer/user.go
+2
-0
routers/controllers/user.go
routers/controllers/user.go
+29
-0
routers/router.go
routers/router.go
+4
-0
service/user/login.go
service/user/login.go
+32
-1
service/vas/qq.go
service/vas/qq.go
+19
-0
未找到文件。
models/user.go
浏览文件 @
7c07b623
...
...
@@ -172,6 +172,13 @@ func GetActiveUserByID(ID interface{}) (User, error) {
return
user
,
result
.
Error
}
// GetActiveUserByOpenID 用OpenID获取可登录用户
func
GetActiveUserByOpenID
(
openid
string
)
(
User
,
error
)
{
var
user
User
result
:=
DB
.
Set
(
"gorm:auto_preload"
,
true
)
.
Where
(
"status = ? and open_id = ?"
,
Active
,
openid
)
.
Find
(
&
user
)
return
user
,
result
.
Error
}
// GetUserByEmail 用Email获取用户
func
GetUserByEmail
(
email
string
)
(
User
,
error
)
{
var
user
User
...
...
pkg/serializer/user.go
浏览文件 @
7c07b623
...
...
@@ -25,6 +25,7 @@ type User struct {
CreatedAt
int64
`json:"created_at"`
PreferredTheme
string
`json:"preferred_theme"`
Score
int
`json:"score"`
Anonymous
bool
`json:"anonymous"`
Policy
policy
`json:"policy"`
Group
group
`json:"group"`
Tags
[]
tag
`json:"tags"`
...
...
@@ -97,6 +98,7 @@ func BuildUser(user model.User) User {
CreatedAt
:
user
.
CreatedAt
.
Unix
(),
PreferredTheme
:
user
.
OptionsSerialized
.
PreferredTheme
,
Score
:
user
.
Score
,
Anonymous
:
user
.
IsAnonymous
(),
Policy
:
policy
{
SaveType
:
user
.
Policy
.
Type
,
MaxSize
:
fmt
.
Sprintf
(
"%.2fmb"
,
float64
(
user
.
Policy
.
MaxSize
)
/
(
1024
*
1024
)),
...
...
routers/controllers/user.go
浏览文件 @
7c07b623
...
...
@@ -5,6 +5,7 @@ import (
"fmt"
model
"github.com/HFO4/cloudreve/models"
"github.com/HFO4/cloudreve/pkg/authn"
"github.com/HFO4/cloudreve/pkg/qq"
"github.com/HFO4/cloudreve/pkg/serializer"
"github.com/HFO4/cloudreve/pkg/thumb"
"github.com/HFO4/cloudreve/pkg/util"
...
...
@@ -126,6 +127,34 @@ func UserLogin(c *gin.Context) {
}
else
{
c
.
JSON
(
200
,
ErrorResponse
(
err
))
}
}
// User2FALogin 用户二步验证登录
func
User2FALogin
(
c
*
gin
.
Context
)
{
var
service
user
.
Enable2FA
if
err
:=
c
.
ShouldBindJSON
(
&
service
);
err
==
nil
{
res
:=
service
.
Login
(
c
)
c
.
JSON
(
200
,
res
)
}
else
{
c
.
JSON
(
200
,
ErrorResponse
(
err
))
}
}
// UserQQLogin 初始化QQ登录
func
UserQQLogin
(
c
*
gin
.
Context
)
{
// 新建绑定
res
,
err
:=
qq
.
NewLoginRequest
()
if
err
!=
nil
{
c
.
JSON
(
200
,
serializer
.
Err
(
serializer
.
CodeNotSet
,
"无法使用QQ登录"
,
err
))
return
}
// 设定QQ登录会话Secret
util
.
SetSession
(
c
,
map
[
string
]
interface
{}{
"qq_login_secret"
:
res
.
SecretKey
})
c
.
JSON
(
200
,
serializer
.
Response
{
Data
:
res
.
URL
,
})
}
...
...
routers/router.go
浏览文件 @
7c07b623
...
...
@@ -103,6 +103,10 @@ func InitMasterRouter() *gin.Engine {
{
// 用户登录
user
.
POST
(
"session"
,
controllers
.
UserLogin
)
// 用户登录
user
.
POST
(
"2fa"
,
controllers
.
User2FALogin
)
// 初始化QQ登录
user
.
POST
(
"qq"
,
controllers
.
UserQQLogin
)
// WebAuthn登陆初始化
user
.
GET
(
"authn/:username"
,
middleware
.
IsFunctionEnabled
(
"authn_enabled"
),
...
...
service/user/login.go
浏览文件 @
7c07b623
...
...
@@ -6,6 +6,7 @@ import (
"github.com/HFO4/cloudreve/pkg/util"
"github.com/gin-gonic/gin"
"github.com/mojocn/base64Captcha"
"github.com/pquerna/otp/totp"
)
// UserLoginService 管理用户登录的服务
...
...
@@ -16,6 +17,32 @@ type UserLoginService struct {
CaptchaCode
string
`form:"captchaCode" json:"captchaCode"`
}
// Login 二步验证继续登录
func
(
service
*
Enable2FA
)
Login
(
c
*
gin
.
Context
)
serializer
.
Response
{
if
uid
,
ok
:=
util
.
GetSession
(
c
,
"2fa_user_id"
)
.
(
uint
);
ok
{
// 查找用户
expectedUser
,
err
:=
model
.
GetActiveUserByID
(
uid
)
if
err
!=
nil
{
return
serializer
.
Err
(
serializer
.
CodeNotFound
,
"用户不存在"
,
nil
)
}
// 验证二步验证代码
if
!
totp
.
Validate
(
service
.
Code
,
expectedUser
.
TwoFactor
)
{
return
serializer
.
ParamErr
(
"验证代码不正确"
,
nil
)
}
//登陆成功,清空并设置session
util
.
DeleteSession
(
c
,
"2fa_user_id"
)
util
.
SetSession
(
c
,
map
[
string
]
interface
{}{
"user_id"
:
expectedUser
.
ID
,
})
return
serializer
.
BuildUserResponse
(
expectedUser
)
}
return
serializer
.
Err
(
serializer
.
CodeNotFound
,
"登录会话不存在"
,
nil
)
}
// Login 用户登录函数
func
(
service
*
UserLoginService
)
Login
(
c
*
gin
.
Context
)
serializer
.
Response
{
isCaptchaRequired
:=
model
.
GetSettingByName
(
"login_captcha"
)
...
...
@@ -44,7 +71,11 @@ func (service *UserLoginService) Login(c *gin.Context) serializer.Response {
}
if
expectedUser
.
TwoFactor
!=
""
{
//TODO 二步验证处理
// 需要二步验证
util
.
SetSession
(
c
,
map
[
string
]
interface
{}{
"2fa_user_id"
:
expectedUser
.
ID
,
})
return
serializer
.
Response
{
Code
:
203
}
}
//登陆成功,清空并设置session
...
...
service/vas/qq.go
浏览文件 @
7c07b623
...
...
@@ -16,11 +16,14 @@ type QQCallbackService struct {
// Callback 处理QQ互联回调
func
(
service
*
QQCallbackService
)
Callback
(
c
*
gin
.
Context
,
user
*
model
.
User
)
serializer
.
Response
{
state
:=
util
.
GetSession
(
c
,
"qq_login_secret"
)
if
stateStr
,
ok
:=
state
.
(
string
);
!
ok
||
stateStr
!=
service
.
State
{
return
serializer
.
Err
(
serializer
.
CodeSignExpired
,
"请求过期,请重试"
,
nil
)
}
util
.
DeleteSession
(
c
,
"qq_login_secret"
)
// 获取OpenID
credential
,
err
:=
qq
.
Callback
(
service
.
Code
)
if
err
!=
nil
{
return
serializer
.
Err
(
serializer
.
CodeNotSet
,
"无法获取登录状态"
,
err
)
...
...
@@ -28,6 +31,7 @@ func (service *QQCallbackService) Callback(c *gin.Context, user *model.User) ser
// 如果已登录,则绑定已有用户
if
user
!=
nil
{
if
user
.
OpenID
!=
""
{
return
serializer
.
Err
(
serializer
.
CodeCallbackError
,
"您已绑定了QQ账号,请先解除绑定"
,
nil
)
}
...
...
@@ -37,6 +41,21 @@ func (service *QQCallbackService) Callback(c *gin.Context, user *model.User) ser
return
serializer
.
Response
{
Data
:
"/setting"
,
}
}
// 未登录,尝试查找用户
if
expectedUser
,
err
:=
model
.
GetActiveUserByOpenID
(
credential
.
OpenID
);
err
==
nil
{
// 用户绑定了此QQ,设定为登录状态
util
.
SetSession
(
c
,
map
[
string
]
interface
{}{
"user_id"
:
expectedUser
.
ID
,
})
res
:=
serializer
.
BuildUserResponse
(
expectedUser
)
res
.
Code
=
203
return
res
}
else
{
// 无匹配用户,创建新用户
}
return
serializer
.
Response
{}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录