Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
MaxKey单点登录官方(MaxKeyTop)
MaxKey
提交
af25f72a
MaxKey
项目概览
MaxKey单点登录官方(MaxKeyTop)
/
MaxKey
9 个月 前同步成功
通知
75
Star
3
Fork
1
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
MaxKey
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
af25f72a
编写于
5月 12, 2023
作者:
Z
zen
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
增加一次性动态口令验证功能
上级
458d4854
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
69 addition
and
11 deletion
+69
-11
maxkey-web-frontend/maxkey-web-app/src/app/entity/TimeBased.ts
...y-web-frontend/maxkey-web-app/src/app/entity/TimeBased.ts
+1
-0
maxkey-web-frontend/maxkey-web-app/src/app/routes/config/timebased/timebased.component.html
.../src/app/routes/config/timebased/timebased.component.html
+21
-7
maxkey-web-frontend/maxkey-web-app/src/app/routes/config/timebased/timebased.component.ts
...pp/src/app/routes/config/timebased/timebased.component.ts
+17
-1
maxkey-web-frontend/maxkey-web-app/src/app/service/time-based.service.ts
...tend/maxkey-web-app/src/app/service/time-based.service.ts
+4
-0
maxkey-web-frontend/maxkey-web-app/src/assets/i18n/en-US.json
...ey-web-frontend/maxkey-web-app/src/assets/i18n/en-US.json
+3
-1
maxkey-web-frontend/maxkey-web-app/src/assets/i18n/zh-CN.json
...ey-web-frontend/maxkey-web-app/src/assets/i18n/zh-CN.json
+3
-1
maxkey-web-frontend/maxkey-web-app/src/assets/i18n/zh-TW.json
...ey-web-frontend/maxkey-web-app/src/assets/i18n/zh-TW.json
+3
-1
maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/contorller/OneTimePasswordController.java
.../org/maxkey/web/contorller/OneTimePasswordController.java
+17
-0
未找到文件。
maxkey-web-frontend/maxkey-web-app/src/app/entity/TimeBased.ts
浏览文件 @
af25f72a
...
...
@@ -26,4 +26,5 @@ export class TimeBased extends BaseEntity {
sharedSecret
!
:
String
;
hexSharedSecret
!
:
String
;
rqCode
!
:
String
;
otp
!
:
string
;
}
maxkey-web-frontend/maxkey-web-app/src/app/routes/config/timebased/timebased.component.html
浏览文件 @
af25f72a
...
...
@@ -14,7 +14,7 @@
<nz-form-control
[nzSm]=
"14"
[nzXs]=
"36"
[nzXl]=
"48"
nzErrorTip=
"The input is not displayName!"
>
<input
nz-input
readonly
[disabled]=
"isDisabled"
[(ngModel)]=
"form.model.displayName"
[ngModelOptions]=
"{ standalone: true }"
name=
"displayName"
...
...
@@ -28,7 +28,7 @@
<nz-form-control
[nzSm]=
"14"
[nzXs]=
"24"
nzErrorTip=
"The input is not valid username!"
>
<input
nz-input
readonly
[disabled]=
"isDisabled"
[(ngModel)]=
"form.model.username"
[ngModelOptions]=
"{ standalone: true }"
name=
"username"
...
...
@@ -39,13 +39,13 @@
<nz-form-item>
<nz-form-label
[nzSm]=
"6"
[nzXs]=
"24"
nzFor=
"digits"
>
{{ 'mxk.timebased.digits' | i18n }}
</nz-form-label>
<nz-form-control
[nzSm]=
"14"
[nzXs]=
"24"
nzErrorTip=
"The input is not valid digits!"
>
<input
nz-input
readonly
[(ngModel)]=
"form.model.digits"
[ngModelOptions]=
"{ standalone: true }"
name=
"digits"
id=
"digits"
/>
<input
nz-input
[disabled]=
"isDisabled"
[(ngModel)]=
"form.model.digits"
[ngModelOptions]=
"{ standalone: true }"
name=
"digits"
id=
"digits"
/>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label
[nzSm]=
"6"
[nzXs]=
"24"
nzFor=
"period"
>
{{ 'mxk.timebased.period' | i18n }}
</nz-form-label>
<nz-form-control
[nzSm]=
"14"
[nzXs]=
"24"
nzErrorTip=
"The input is not valid period!"
>
<input
nz-input
readonly
[(ngModel)]=
"form.model.period"
[ngModelOptions]=
"{ standalone: true }"
name=
"period"
id=
"period"
/>
<input
nz-input
[disabled]=
"isDisabled"
[(ngModel)]=
"form.model.period"
[ngModelOptions]=
"{ standalone: true }"
name=
"period"
id=
"period"
/>
</nz-form-control>
</nz-form-item>
<nz-form-item>
...
...
@@ -53,7 +53,7 @@
<nz-form-control
[nzSm]=
"14"
[nzXs]=
"24"
nzErrorTip=
"The input is not valid sharedSecret!"
>
<input
nz-input
readonly
[disabled]=
"isDisabled"
[(ngModel)]=
"form.model.sharedSecret"
[ngModelOptions]=
"{ standalone: true }"
name=
"sharedSecret"
...
...
@@ -66,7 +66,7 @@
<nz-form-control
[nzSm]=
"14"
[nzXs]=
"24"
nzErrorTip=
"The input is not valid hexSharedSecret!"
>
<input
nz-input
readonly
[disabled]=
"isDisabled"
[(ngModel)]=
"form.model.hexSharedSecret"
[ngModelOptions]=
"{ standalone: true }"
name=
"hexSharedSecret"
...
...
@@ -74,10 +74,24 @@
/>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label
[nzSm]=
"6"
[nzXs]=
"24"
nzFor=
"one-timePassword"
>
{{ 'mxk.timebased.one-timePassword' | i18n }}
</nz-form-label>
<nz-form-control
[nzSm]=
"14"
[nzXs]=
"24"
nzErrorTip=
"The input is not valid One-Time Password!"
>
<input
nz-input
[(ngModel)]=
"form.model.otp"
[ngModelOptions]=
"{ standalone: true }"
placeholder=
"请在生成后输入一次性密码用于验证"
name=
"oneTimePassword"
id=
"oneTimePassword"
/>
</nz-form-control>
</nz-form-item>
<nz-form-item
style=
"width: 100%"
>
<nz-form-control
[nzOffset]=
"7"
[nzSpan]=
"
12
"
>
<nz-form-control
[nzOffset]=
"7"
[nzSpan]=
"
3
"
>
<button
nz-button
nzType=
"primary"
type=
"submit"
[nzLoading]=
"form.submitting"
>
{{ 'mxk.text.generate' | i18n }}
</button>
</nz-form-control>
<button
nz-button
nzType=
"primary"
(click)=
"verify($event,form.model.otp)"
>
{{ 'mxk.text.verify' | i18n }}
</button>
</nz-form-item>
</div>
</div>
...
...
maxkey-web-frontend/maxkey-web-app/src/app/routes/config/timebased/timebased.component.ts
浏览文件 @
af25f72a
...
...
@@ -28,7 +28,7 @@ import { Console } from 'console';
@
Component
({
selector
:
'
app-timebased
'
,
templateUrl
:
'
./timebased.component.html
'
,
styleUrls
:
[
'
./timebased.component.less
'
]
styleUrls
:
[
'
./timebased.component.less
'
]
,
})
export
class
TimebasedComponent
implements
OnInit
{
form
:
{
...
...
@@ -39,6 +39,8 @@ export class TimebasedComponent implements OnInit {
model
:
new
TimeBased
()
};
isDisabled
=
true
;
formGroup
:
FormGroup
=
new
FormGroup
({});
constructor
(
...
...
@@ -87,4 +89,18 @@ export class TimebasedComponent implements OnInit {
this
.
cdr
.
detectChanges
();
});
}
verify
(
e
:
MouseEvent
,
otp
:
string
):
void
{
e
.
preventDefault
();
this
.
timeBasedService
.
verify
(
otp
).
subscribe
(
res
=>
{
if
(
res
.
code
==
0
)
{
this
.
msg
.
success
(
`验证成功`
);
}
else
{
this
.
msg
.
error
(
'
验证失败
'
);
}
})
// this.timeBasedService.verify(otp)
}
protected
readonly
String
=
String
;
}
maxkey-web-frontend/maxkey-web-app/src/app/service/time-based.service.ts
浏览文件 @
af25f72a
...
...
@@ -37,4 +37,8 @@ export class TimeBasedService extends BaseService<TimeBased> {
override
update
(
body
:
any
):
Observable
<
Message
<
TimeBased
>>
{
return
this
.
http
.
get
<
Message
<
TimeBased
>>
(
`
${
this
.
server
.
urls
.
base
}
/timebased?generate=YES`
);
}
verify
(
otp
:
string
):
Observable
<
Message
<
TimeBased
>>
{
return
this
.
http
.
get
<
Message
<
TimeBased
>>
(
`
${
this
.
server
.
urls
.
base
}
/verify?otp=`
+
otp
);
}
}
maxkey-web-frontend/maxkey-web-app/src/assets/i18n/en-US.json
浏览文件 @
af25f72a
...
...
@@ -543,7 +543,8 @@
"period"
:
"period"
,
"sharedSecret"
:
"sharedSecret(BASE32)"
,
"hexSharedSecret"
:
"sharedSecret( HEX )"
,
"rqCode"
:
"RQCode"
"rqCode"
:
"RQCode"
,
"one-timePassword"
:
"One-Time Password"
},
"socialsproviders"
:
{
"icon"
:
"Icon"
,
...
...
@@ -683,6 +684,7 @@
"close"
:
"Close"
,
"submit"
:
"Submit"
,
"generate"
:
"Generate"
,
"verify"
:
"Verify"
,
"upload"
:
"Upload"
,
"save"
:
"Save"
,
"year"
:
"Year"
,
...
...
maxkey-web-frontend/maxkey-web-app/src/assets/i18n/zh-CN.json
浏览文件 @
af25f72a
...
...
@@ -529,7 +529,8 @@
"period"
:
"周期"
,
"sharedSecret"
:
"共享密钥(BASE32)"
,
"hexSharedSecret"
:
"共享密钥( HEX )"
,
"rqCode"
:
"二维码"
"rqCode"
:
"二维码"
,
"one-timePassword"
:
"一次性密码"
},
"socialsassociate"
:
{
"icon"
:
"图标"
,
...
...
@@ -686,6 +687,7 @@
"close"
:
"关闭"
,
"submit"
:
"提交"
,
"generate"
:
"生成"
,
"verify"
:
"验证"
,
"upload"
:
"上传"
,
"save"
:
"保存"
,
"year"
:
"年"
,
...
...
maxkey-web-frontend/maxkey-web-app/src/assets/i18n/zh-TW.json
浏览文件 @
af25f72a
...
...
@@ -529,7 +529,8 @@
"period"
:
"週期"
,
"sharedSecret"
:
"共享密鑰(BASE32)"
,
"hexSharedSecret"
:
"共享密鑰( HEX )"
,
"rqCode"
:
"二維碼"
"rqCode"
:
"二維碼"
,
"one-timePassword"
:
"一次性密碼"
},
"socialsassociate"
:
{
"icon"
:
"圖標"
,
...
...
@@ -686,6 +687,7 @@
"close"
:
"關閉"
,
"submit"
:
"提交"
,
"generate"
:
"生成"
,
"verify"
:
"驗證"
,
"upload"
:
"上傳"
,
"save"
:
"保存"
,
"year"
:
"年"
,
...
...
maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/contorller/OneTimePasswordController.java
浏览文件 @
af25f72a
...
...
@@ -30,6 +30,7 @@ import org.maxkey.entity.Message;
import
org.maxkey.entity.UserInfo
;
import
org.maxkey.password.onetimepwd.algorithm.OtpKeyUriFormat
;
import
org.maxkey.password.onetimepwd.algorithm.OtpSecret
;
import
org.maxkey.password.onetimepwd.impl.TimeBasedOtpAuthn
;
import
org.maxkey.persistence.service.UserInfoService
;
import
org.maxkey.util.RQCodeUtils
;
import
org.slf4j.Logger
;
...
...
@@ -58,6 +59,9 @@ public class OneTimePasswordController {
@Autowired
OtpKeyUriFormat
otpKeyUriFormat
;
@Autowired
private
TimeBasedOtpAuthn
timeBasedOtpAuthn
;
@RequestMapping
(
value
=
{
"/timebased"
})
@ResponseBody
public
ResponseEntity
<?>
timebased
(
...
...
@@ -99,5 +103,18 @@ public class OneTimePasswordController {
}
}
@RequestMapping
(
"/verify"
)
public
ResponseEntity
<?>
verify
(
@RequestParam
(
"otp"
)
String
otp
,
@CurrentUser
UserInfo
currentUser
)
{
// 从当前用户信息中获取共享密钥
String
sharedSecret
=
PasswordReciprocal
.
getInstance
().
decoder
(
currentUser
.
getSharedSecret
());
// 计算当前时间对应的动态密码
boolean
validate
=
timeBasedOtpAuthn
.
validate
(
currentUser
,
otp
);
if
(
validate
)
{
return
new
Message
<>(
0
,
"One-Time Password verification succeeded"
).
buildResponse
();
}
else
{
return
new
Message
<>(
2
,
"One-Time Password verification failed"
).
buildResponse
();
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录