二次认证的配置

This commit is contained in:
shimingxy 2025-05-22 16:54:10 +08:00
parent 7bd53e325a
commit 3f5d4e4bf6
25 changed files with 391 additions and 70 deletions

View File

@ -17,6 +17,7 @@
package org.dromara.maxkey.entity.idm; package org.dromara.maxkey.entity.idm;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import java.io.Serializable; import java.io.Serializable;
@ -130,6 +131,7 @@ public class UserInfo extends JpaEntity implements Serializable {
// for security // for security
@Column @Column
@JsonFormat(shape = JsonFormat.Shape.STRING)
protected int authnType; protected int authnType;
@Column @Column
protected String email; protected String email;

View File

@ -28,6 +28,7 @@ import { NzPaginationModule } from 'ng-zorro-antd/pagination';
import { NzStepsModule } from 'ng-zorro-antd/steps'; import { NzStepsModule } from 'ng-zorro-antd/steps';
import { AccoutsComponent } from './accouts/accouts.component'; import { AccoutsComponent } from './accouts/accouts.component';
import { MfaComponent } from './mfa/mfa.component';
import { PasswordComponent } from './password/password.component'; import { PasswordComponent } from './password/password.component';
import { ProfileComponent } from './profile/profile.component'; import { ProfileComponent } from './profile/profile.component';
import { SocialsAssociateComponent } from './socials-associate/socials-associate.component'; import { SocialsAssociateComponent } from './socials-associate/socials-associate.component';
@ -50,6 +51,10 @@ const routes: Routes = [
{ {
path: 'timebased', path: 'timebased',
component: TimebasedComponent component: TimebasedComponent
},
{
path: 'mfa',
component: MfaComponent
} }
]; ];
@ -63,7 +68,8 @@ const COMPONENTS = [ProfileComponent];
SocialsAssociateComponent, SocialsAssociateComponent,
PasswordComponent, PasswordComponent,
ProfileComponent, ProfileComponent,
AccoutsComponent AccoutsComponent,
MfaComponent
], ],
imports: [SharedModule, CommonModule, RouterModule.forChild(routes)], imports: [SharedModule, CommonModule, RouterModule.forChild(routes)],
exports: [RouterModule] exports: [RouterModule]

View File

@ -0,0 +1,55 @@
<nz-card>
<form nz-form (ngSubmit)="onSubmit()">
<div nz-row style="width: 100%">
<div nz-col nzMd="16">
<nz-form-item style="display: none">
<nz-form-label [nzMd]="6" nzFor="id">id</nz-form-label>
<nz-form-control [nzMd]="18" nzErrorTip="The input is not valid id!">
<input [(ngModel)]="form.model.id" [ngModelOptions]="{ standalone: true }" nz-input name="id" id="id" value="id" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzFor="displayName">{{ 'mxk.password.displayName' | i18n }}</nz-form-label>
<nz-form-control [nzSm]="14" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not displayName!">
<input nz-input disabled="true" [(ngModel)]="form.model.displayName" [ngModelOptions]="{ standalone: true }" value="0" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzFor="username">{{ 'mxk.password.username' | i18n }}</nz-form-label>
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="The input is not valid username!">
<input nz-input disabled="true" [(ngModel)]="form.model.username" [ngModelOptions]="{ standalone: true }" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzFor="mobile">{{ 'mxk.users.mobile' | i18n }}</nz-form-label>
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="The input is not valid mobile!">
<input nz-input disabled="true" [(ngModel)]="form.model.mobile" [ngModelOptions]="{ standalone: true }" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzFor="email">{{ 'mxk.users.email' | i18n }}</nz-form-label>
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="The input is not valid email!">
<input nz-input disabled="true" [(ngModel)]="form.model.email" [ngModelOptions]="{ standalone: true }" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSm]="6" [nzXs]="24" nzFor="authnType">{{ 'mxk.users.authnType' | i18n }}</nz-form-label>
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="The input is not valid authnType!">
<nz-radio-group [(ngModel)]="form.model.authnType" [ngModelOptions]="{ standalone: true }" nzButtonStyle="solid">
<label nz-radio-button nzValue="0">{{ 'mxk.users.authnType.0' | i18n }}</label>
<label nz-radio-button nzValue="1">{{ 'mxk.users.authnType.1' | i18n }}</label>
<label nz-radio-button nzValue="2">{{ 'mxk.users.authnType.2' | i18n }}</label>
<label nz-radio-button nzValue="3">{{ 'mxk.users.authnType.3' | i18n }}</label>
</nz-radio-group>
</nz-form-control>
</nz-form-item>
<nz-form-item style="width: 100%">
<nz-form-control [nzOffset]="10" [nzSpan]="12">
<button nz-button nzType="primary" type="submit" [nzLoading]="form.submitting">{{ 'mxk.text.save' | i18n }}</button>
</nz-form-control>
</nz-form-item>
</div>
</div>
</form>
</nz-card>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MfaComponent } from './mfa.component';
describe('MfaComponent', () => {
let component: MfaComponent;
let fixture: ComponentFixture<MfaComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ MfaComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(MfaComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,63 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, Inject } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router, ActivatedRoute } from '@angular/router';
import { I18NService } from '@core';
import { SettingsService, User, ALAIN_I18N_TOKEN } from '@delon/theme';
import { NzMessageService } from 'ng-zorro-antd/message';
import { Users } from '../../../entity/Users';
import { UsersService } from '../../../service/users.service';
@Component({
selector: 'app-mfa',
templateUrl: './mfa.component.html',
styleUrls: ['./mfa.component.less']
})
export class MfaComponent implements OnInit {
form: {
submitting: boolean;
model: Users;
} = {
submitting: false,
model: new Users()
};
loading = false;
constructor(
private router: Router,
private fb: FormBuilder,
private settingsService: SettingsService,
private usersService: UsersService,
private msg: NzMessageService,
@Inject(ALAIN_I18N_TOKEN) private i18n: I18NService,
private cdr: ChangeDetectorRef
) {}
ngOnInit(): void {
let user: any = this.settingsService.user;
this.form.model.id = user.userId;
this.form.model.displayName = user.displayName;
this.form.model.username = user.username;
this.form.model.mobile = user.mobile;
this.form.model.email = user.email;
this.form.model.authnType = '0';
this.usersService.getProfile().subscribe(res => {
this.form.model.init(res.data);
this.cdr.detectChanges();
});
}
onSubmit(): void {
this.form.submitting = true;
this.form.model.trans();
this.usersService.updateAuthnType(this.form.model).subscribe(res => {
if (res.code == 0) {
this.msg.success(this.i18n.fanyi('mxk.alert.operate.success'));
} else {
this.msg.error(this.i18n.fanyi('mxk.alert.operate.error'));
}
this.form.submitting = false;
this.cdr.detectChanges();
});
}
}

View File

@ -44,4 +44,8 @@ export class UsersService extends BaseService<Users> {
updateProfile(body: any): Observable<Message<Users>> { updateProfile(body: any): Observable<Message<Users>> {
return this.http.put<Message<Users>>('/users/profile/update', body); return this.http.put<Message<Users>>('/users/profile/update', body);
} }
updateAuthnType(body: any): Observable<Message<Users>> {
return this.http.put<Message<Users>>('/users/profile/updateAuthnType', body);
}
} }

View File

@ -43,6 +43,14 @@
"icon": "anticon-appstore", "icon": "anticon-appstore",
"acl": "ROLE_USER", "acl": "ROLE_USER",
"children": [] "children": []
},
{
"text": "二次认证",
"i18n": "mxk.menu.config.mfa",
"link": "/config/mfa",
"icon": "anticon-appstore",
"acl": "ROLE_USER",
"children": []
}, },
{ {
"text": "密码修改", "text": "密码修改",

View File

@ -44,6 +44,7 @@
"": "Settings", "": "Settings",
"setting": "Setting", "setting": "Setting",
"profile": "Profile", "profile": "Profile",
"mfa": "MFA",
"password": "Password", "password": "Password",
"socialsassociate": "Socials", "socialsassociate": "Socials",
"timebased": "OTP Token" "timebased": "OTP Token"
@ -162,17 +163,11 @@
"userstate.withdrawn": "Withdrawn", "userstate.withdrawn": "Withdrawn",
"userstate.inactive": "Inactive", "userstate.inactive": "Inactive",
"userstate.retiree": "Retiree", "userstate.retiree": "Retiree",
"authnType": "AuthenticationType", "authnType": "MFA Type",
"authnType.authnType.1": "General login", "authnType.0": "None",
"authnType.authnType.2": "Mobile Token", "authnType.1": "TOTP",
"authnType.authnType.3": "SMS Verification", "authnType.2": "Mail OTP",
"authnType.authnType.4": "EMAIL Verification", "authnType.3": "SMS OTP"
"authnType.authnType.5": "TIME BASED Token",
"authnType.authnType.6": "Counter Token",
"authnType.authnType.7": "HOTP Token",
"authnType.authnType.8": "RSA Token",
"authnType.authnType.9": "Digital Certificate",
"authnType.authnType.10": "USB Key"
}, },
"organizations": { "organizations": {
"tab.basic": "Basic", "tab.basic": "Basic",

View File

@ -44,6 +44,7 @@
"": "配置", "": "配置",
"setting": "基本设置", "setting": "基本设置",
"profile": "我的资料", "profile": "我的资料",
"mfa": "二次认证",
"socialsassociate": "社交关联", "socialsassociate": "社交关联",
"password": "密码修改", "password": "密码修改",
"timebased": "时间令牌" "timebased": "时间令牌"
@ -166,17 +167,11 @@
"userstate.withdrawn": "离职", "userstate.withdrawn": "离职",
"userstate.inactive": "停薪留职", "userstate.inactive": "停薪留职",
"userstate.retiree": "退休", "userstate.retiree": "退休",
"authnType": "登录方式", "authnType": "二次认证",
"authnType.authnType.1": "普通登录", "authnType.0": "无",
"authnType.authnType.2": "手机令牌", "authnType.1": "TOTP令牌",
"authnType.authnType.3": "短信验证", "authnType.2": "邮件验证码",
"authnType.authnType.4": "邮件验证", "authnType.3": "短信验证码"
"authnType.authnType.5": "时间令牌",
"authnType.authnType.6": "计数器令牌",
"authnType.authnType.7": "HOTP令牌",
"authnType.authnType.8": "RSA令牌",
"authnType.authnType.9": "数字证书",
"authnType.authnType.10": "USB Key"
}, },
"organizations": { "organizations": {
"tab.basic": "基本信息", "tab.basic": "基本信息",

View File

@ -44,6 +44,7 @@
"": "配置", "": "配置",
"setting": "基本設置", "setting": "基本設置",
"profile": "我的資料", "profile": "我的資料",
"mfa": "二次认证",
"socialsassociate": "社交關聯", "socialsassociate": "社交關聯",
"password": "密碼修改", "password": "密碼修改",
"timebased": "時間令牌" "timebased": "時間令牌"
@ -166,17 +167,11 @@
"userstate.withdrawn": "離職", "userstate.withdrawn": "離職",
"userstate.inactive": "停薪留職", "userstate.inactive": "停薪留職",
"userstate.retiree": "退休", "userstate.retiree": "退休",
"authnType": "登錄方式", "authnType": "二次认证",
"authnType.authnType.1": "普通登錄", "authnType.0": "无",
"authnType.authnType.2": "手機令牌", "authnType.1": "TOTP令牌",
"authnType.authnType.3": "短信驗證", "authnType.2": "邮件验证码",
"authnType.authnType.4": "郵件驗證", "authnType.3": "短信验证码"
"authnType.authnType.5": "時間令牌",
"authnType.authnType.6": "計數器令牌",
"authnType.authnType.7": "HOTP令牌",
"authnType.authnType.8": "RSA令牌",
"authnType.authnType.9": "數字證書",
"authnType.authnType.10": "USB Key"
}, },
"organizations": { "organizations": {
"tab.basic": "基本信息", "tab.basic": "基本信息",

View File

@ -27,8 +27,8 @@ export const environment = {
production: false, production: false,
useHash: true, useHash: true,
api: { api: {
baseUrl: 'http://sso.maxkey.top/sign/', //baseUrl: 'http://sso.maxkey.top/sign/',
// baseUrl: '/sign/', baseUrl: 'http://localhost:9527/sign/',
refreshTokenEnabled: true, refreshTokenEnabled: true,
refreshTokenType: 're-request' refreshTokenType: 're-request'
}, },

View File

@ -29,6 +29,7 @@ import { GroupsComponent } from './groups/groups.component';
import { SelectGroupsComponent } from './groups/select-groups/select-groups.component'; import { SelectGroupsComponent } from './groups/select-groups/select-groups.component';
import { OrganizationEditerComponent } from './organizations/organization-editer/organization-editer.component'; import { OrganizationEditerComponent } from './organizations/organization-editer/organization-editer.component';
import { OrganizationsComponent } from './organizations/organizations.component'; import { OrganizationsComponent } from './organizations/organizations.component';
import { MfaComponent } from './users/mfa/mfa.component';
import { PasswordComponent } from './users/password/password.component'; import { PasswordComponent } from './users/password/password.component';
import { SelectUserComponent } from './users/select-user/select-user.component'; import { SelectUserComponent } from './users/select-user/select-user.component';
import { UserEditerComponent } from './users/user-editer/user-editer.component'; import { UserEditerComponent } from './users/user-editer/user-editer.component';
@ -57,7 +58,7 @@ const COMPONENTS = [
]; ];
@NgModule({ @NgModule({
declarations: [...COMPONENTS], declarations: [...COMPONENTS, MfaComponent],
imports: [FormsModule, NzIconModule, SharedModule, CommonModule, RouterModule.forChild(routes)], imports: [FormsModule, NzIconModule, SharedModule, CommonModule, RouterModule.forChild(routes)],
exports: [RouterModule] exports: [RouterModule]
}) })

View File

@ -0,0 +1,39 @@
<div *nzModalTitle> {{ 'mxk.users.authnType' | i18n }} </div>
<div>
<form nz-form (ngSubmit)="onSubmit($event)" se-container="1">
<nz-form-item style="width: 100%" class="d-none">
<nz-form-label [nzSm]="6" [nzXs]="24" nzFor="id">{{ 'mxk.users.id' | i18n }} </nz-form-label>
<nz-form-control [nzSm]="18" [nzMd]="18" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid id!">
<input [(ngModel)]="form.model.id" [ngModelOptions]="{ standalone: true }" nz-input name="id" id="id" />
</nz-form-control>
</nz-form-item>
<nz-form-item style="width: 100%">
<nz-form-label [nzSm]="6" [nzXs]="24" nzFor="username">{{ 'mxk.users.username' | i18n }} </nz-form-label>
<nz-form-control [nzSm]="18" [nzMd]="18" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid username!">
<input [(ngModel)]="form.model.username" disabled [ngModelOptions]="{ standalone: true }" nz-input />
</nz-form-control>
</nz-form-item>
<nz-form-item style="width: 100%">
<nz-form-label [nzSm]="6" [nzXs]="24" nzFor="displayName">{{ 'mxk.users.displayName' | i18n }} </nz-form-label>
<nz-form-control [nzSm]="18" [nzMd]="18" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not valid displayName!">
<input [(ngModel)]="form.model.displayName" disabled [ngModelOptions]="{ standalone: true }" nz-input />
</nz-form-control>
</nz-form-item>
<nz-form-item style="width: 100%">
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="authnType">{{ 'mxk.users.authnType' | i18n }}</nz-form-label>
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="The input is not valid authnType!">
<nz-select [(ngModel)]="form.model.authnType" [ngModelOptions]="{ standalone: true }">
<nz-option nzValue="0" nzLabel="{{ 'mxk.users.authnType.0' | i18n }}"></nz-option>
<nz-option nzValue="1" nzLabel="{{ 'mxk.users.authnType.1' | i18n }}"></nz-option>
<nz-option nzValue="2" nzLabel="{{ 'mxk.users.authnType.2' | i18n }}"></nz-option>
<nz-option nzValue="3" nzLabel="{{ 'mxk.users.authnType.3' | i18n }}"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
</form>
</div>
<div *nzModalFooter>
<button nz-button nzType="default" (click)="onClose($event)">{{ 'mxk.text.close' | i18n }}</button>
<button nz-button nzType="primary" (click)="onSubmit($event)">{{ 'mxk.text.submit' | i18n }}</button>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MfaComponent } from './mfa.component';
describe('MfaComponent', () => {
let component: MfaComponent;
let fixture: ComponentFixture<MfaComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ MfaComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(MfaComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,65 @@
import { Component, ChangeDetectorRef, OnInit, Input, Inject } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { I18NService } from '@core';
import { ALAIN_I18N_TOKEN, SettingsService } from '@delon/theme';
import { NzMessageService } from 'ng-zorro-antd/message';
import { NzModalRef, NzModalService } from 'ng-zorro-antd/modal';
import { Users } from '../../../../entity/Users';
import { UsersService } from '../../../../service/users.service';
@Component({
selector: 'app-mfa',
templateUrl: './mfa.component.html',
styleUrls: ['./mfa.component.less']
})
export class MfaComponent implements OnInit {
@Input() id?: String;
@Input() username?: String;
@Input() displayName?: String;
form: {
submitting: boolean;
model: Users;
} = {
submitting: false,
model: new Users()
};
constructor(
private usersService: UsersService,
private msg: NzMessageService,
@Inject(ALAIN_I18N_TOKEN) private i18n: I18NService,
private router: Router,
private modalRef: NzModalRef,
private cdr: ChangeDetectorRef
) {}
ngOnInit(): void {
if (this.id) {
this.usersService.get(this.id).subscribe(res => {
this.form.model = res.data;
});
}
}
onClose(e: MouseEvent): void {
e.preventDefault();
this.modalRef.destroy({ refresh: false });
}
onSubmit(e: MouseEvent): void {
e.preventDefault();
this.form.submitting = true;
this.usersService.updateAuthnType(this.form.model).subscribe(res => {
if (res.code == 0) {
this.msg.success(this.i18n.fanyi('mxk.alert.operate.success'));
this.modalRef.destroy({ refresh: true });
this.cdr.detectChanges();
} else {
this.msg.error(res.message);
}
});
}
}

View File

@ -168,6 +168,7 @@
<li nz-menu-item *ngIf="data.status == 1" (click)="changePasswordById($event, data.id)">{{ <li nz-menu-item *ngIf="data.status == 1" (click)="changePasswordById($event, data.id)">{{
'mxk.text.changepassword' | i18n 'mxk.text.changepassword' | i18n
}}</li> }}</li>
<li nz-menu-item *ngIf="data.status == 1" (click)="changeMfaById(data.id)">{{ 'mxk.users.authnType' | i18n }}</li>
<li nz-menu-item *ngIf="data.status == 1" (click)="onUpdateStatus($event, data.id, 5)">{{ 'mxk.text.lock' | i18n }}</li> <li nz-menu-item *ngIf="data.status == 1" (click)="onUpdateStatus($event, data.id, 5)">{{ 'mxk.text.lock' | i18n }}</li>
<li nz-menu-item *ngIf="data.status == 1" (click)="onUpdateStatus($event, data.id, 4)">{{ <li nz-menu-item *ngIf="data.status == 1" (click)="onUpdateStatus($event, data.id, 4)">{{
'mxk.text.disable' | i18n 'mxk.text.disable' | i18n

View File

@ -33,6 +33,7 @@ import { TreeNodes } from '../../../entity/TreeNodes';
import { OrganizationsService } from '../../../service/organizations.service'; import { OrganizationsService } from '../../../service/organizations.service';
import { UsersService } from '../../../service/users.service'; import { UsersService } from '../../../service/users.service';
import { set2String } from '../../../shared/index'; import { set2String } from '../../../shared/index';
import { MfaComponent } from './mfa/mfa.component';
import { PasswordComponent } from './password/password.component'; import { PasswordComponent } from './password/password.component';
import { UserEditerComponent } from './user-editer/user-editer.component'; import { UserEditerComponent } from './user-editer/user-editer.component';
@ -150,6 +151,7 @@ export class UsersComponent implements OnInit {
nzWidth: 450, nzWidth: 450,
nzOnOk: () => new Promise(resolve => setTimeout(resolve, 1000)) nzOnOk: () => new Promise(resolve => setTimeout(resolve, 1000))
}); });
break;
} }
} }
} }
@ -218,6 +220,26 @@ export class UsersComponent implements OnInit {
}); });
} }
changeMfaById(userId: String): void {
for (var i = 0; i < this.query.results.rows.length; i++) {
let user = this.query.results.rows[i];
if (userId == user.id) {
const modal = this.modal.create({
nzContent: MfaComponent,
nzViewContainerRef: this.viewContainerRef,
nzComponentParams: {
id: user.id,
username: user.username,
displayName: user.displayName
},
nzWidth: 450,
nzOnOk: () => new Promise(resolve => setTimeout(resolve, 1000))
});
break;
}
}
}
onNavToUrl(e: MouseEvent, userId: String, username: String, navType: String) { onNavToUrl(e: MouseEvent, userId: String, username: String, navType: String) {
e.preventDefault(); e.preventDefault();
if (navType === 'groups') { if (navType === 'groups') {

View File

@ -48,4 +48,8 @@ export class UsersService extends BaseService<Users> {
params: this.parseParams(params) params: this.parseParams(params)
}); });
} }
updateAuthnType(params: NzSafeAny): Observable<Message<Users>> {
return this.http.put<Message<Users>>(`${this.server.urls.base}/updateAuthnType`, params);
}
} }

View File

@ -180,17 +180,11 @@
"userstate.withdrawn": "Withdrawn", "userstate.withdrawn": "Withdrawn",
"userstate.inactive": "Inactive", "userstate.inactive": "Inactive",
"userstate.retiree": "Retiree", "userstate.retiree": "Retiree",
"authnType": "AuthenticationType", "authnType": "MFA Type",
"authnType.authnType.1": "General login", "authnType.0": "None",
"authnType.authnType.2": "Mobile Token", "authnType.1": "TOTP",
"authnType.authnType.3": "SMS Verification", "authnType.2": "Mail OTP",
"authnType.authnType.4": "EMAIL Verification", "authnType.3": "SMS OTP"
"authnType.authnType.5": "TIME BASED Token",
"authnType.authnType.6": "Counter Token",
"authnType.authnType.7": "HOTP Token",
"authnType.authnType.8": "RSA Token",
"authnType.authnType.9": "Digital Certificate",
"authnType.authnType.10": "USB Key"
}, },
"organizations": { "organizations": {
"tab.basic": "Basic", "tab.basic": "Basic",

View File

@ -180,17 +180,11 @@
"userstate.withdrawn": "离职", "userstate.withdrawn": "离职",
"userstate.inactive": "停薪留职", "userstate.inactive": "停薪留职",
"userstate.retiree": "退休", "userstate.retiree": "退休",
"authnType": "登录方式", "authnType": "二次认证",
"authnType.authnType.1": "普通登录", "authnType.0": "无",
"authnType.authnType.2": "手机令牌", "authnType.1": "TOTP令牌",
"authnType.authnType.3": "短信验证", "authnType.2": "邮件验证码",
"authnType.authnType.4": "邮件验证", "authnType.3": "短信验证码"
"authnType.authnType.5": "时间令牌",
"authnType.authnType.6": "计数器令牌",
"authnType.authnType.7": "HOTP令牌",
"authnType.authnType.8": "RSA令牌",
"authnType.authnType.9": "数字证书",
"authnType.authnType.10": "USB Key"
}, },
"organizations": { "organizations": {
"tab.basic": "基本信息", "tab.basic": "基本信息",

View File

@ -181,17 +181,11 @@
"userstate.withdrawn": "離職", "userstate.withdrawn": "離職",
"userstate.inactive": "停薪留職", "userstate.inactive": "停薪留職",
"userstate.retiree": "退休", "userstate.retiree": "退休",
"authnType": "登錄方式", "authnType": "二次认证",
"authnType.authnType.1": "普通登錄", "authnType.0": "无",
"authnType.authnType.2": "手機令牌", "authnType.1": "TOTP令牌",
"authnType.authnType.3": "短信驗證", "authnType.2": "邮件验证码",
"authnType.authnType.4": "郵件驗證", "authnType.3": "短信验证码"
"authnType.authnType.5": "時間令牌",
"authnType.authnType.6": "計數器令牌",
"authnType.authnType.7": "HOTP令牌",
"authnType.authnType.8": "RSA令牌",
"authnType.authnType.9": "數字證書",
"authnType.authnType.10": "USB Key"
}, },
"organizations": { "organizations": {
"tab.basic": "基本信息", "tab.basic": "基本信息",

View File

@ -90,5 +90,22 @@ public class ProfileController {
return new Message<UserInfo>(Message.FAIL); return new Message<UserInfo>(Message.FAIL);
} }
/**
* AuthnType.
*
* @param userInfo
* @param result
* @return
*/
@PutMapping("/updateAuthnType")
public Message<UserInfo> updateAuthnType(@RequestBody UserInfo userInfo,@CurrentUser UserInfo currentUser) {
userInfo.setId(currentUser.getId());
logger.debug("updateAuthnType {}",userInfo);
if (userInfoService.updateAuthnType(userInfo)) {
return new Message<>(Message.SUCCESS);
}
return new Message<>(Message.FAIL);
}
} }

View File

@ -59,6 +59,7 @@ import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
@ -254,6 +255,22 @@ public class UserInfoController {
} }
} }
/**
* AuthnType.
*
* @param userInfo
* @param result
* @return
*/
@PutMapping("/updateAuthnType")
public Message<UserInfo> updateAuthnType(@RequestBody UserInfo userInfo) {
logger.debug("updateAuthnType {}",userInfo);
if (userInfoService.updateAuthnType(userInfo)) {
return new Message<>(Message.SUCCESS);
}
return new Message<>(Message.FAIL);
}
@RequestMapping(value = "/import") @RequestMapping(value = "/import")
public Message<?> importingUsers( public Message<?> importingUsers(
@ModelAttribute("excelImportFile")ExcelImport excelImportFile, @ModelAttribute("excelImportFile")ExcelImport excelImportFile,