提交 36ea37af 编写于 作者: M MaxKey

jwt login support

上级 f1f41fe7
......@@ -124,8 +124,9 @@ public class AuthJwtService {
JWTClaimsSet claims = resolve(authToken);
boolean isExpiration = claims.getExpirationTime().after(DateTime.now().toDate());
boolean isVerify = hmac512Service.verify(authToken);
_logger.trace("JWT Verify {} , now {} , ExpirationTime {} , isExpiration : {}" ,
isVerify,DateTime.now().toDate(),claims.getExpirationTime(),isExpiration);
_logger.debug("JWT Validate {} , Verify {} , now {} , ExpirationTime {} , isExpiration : {}" ,
isVerify && isExpiration,isVerify,DateTime.now().toDate(),claims.getExpirationTime(),isExpiration);
return isVerify && isExpiration;
}
} catch (ParseException e) {
......
......@@ -54,7 +54,7 @@ public class HttpJwtEntryPoint {
JwtLoginService jwtLoginService;
@RequestMapping(value={"/jwt"}, produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<?> jwt(@RequestParam(value = WebConstants.JWT_TOKEN_PARAMETER, required = false) String jwt) {
public ResponseEntity<?> jwt(@RequestParam(value = WebConstants.JWT_TOKEN_PARAMETER, required = true) String jwt) {
try {
//for jwt Login
_logger.debug("jwt : " + jwt);
......@@ -75,6 +75,32 @@ public class HttpJwtEntryPoint {
return new Message<AuthJwt>(Message.FAIL).buildResponse();
}
/**
* trust same HS512
* @param jwt
* @return
*/
@RequestMapping(value={"/jwt/trust"}, produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<?> jwtTrust(@RequestParam(value = WebConstants.JWT_TOKEN_PARAMETER, required = true) String jwt) {
try {
//for jwt Login
_logger.debug("jwt : " + jwt);
if(authTokenService.validateJwtToken(jwt)) {
String username =authTokenService.resolve(jwt).getSubject();
LoginCredential loginCredential =new LoginCredential(username,"",ConstsLoginType.JWT);
Authentication authentication = authenticationProvider.authenticate(loginCredential,true);
_logger.debug("JWT Logined in , username " + username);
AuthJwt authJwt = authTokenService.genAuthJwt(authentication);
return new Message<AuthJwt>(authJwt).buildResponse();
}
}catch(Exception e) {
_logger.error("Exception ",e);
}
return new Message<AuthJwt>(Message.FAIL).buildResponse();
}
public void setApplicationConfig(ApplicationConfig applicationConfig) {
......
/*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, OnInit, Inject } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ReuseTabService } from '@delon/abc/reuse-tab';
import { DA_SERVICE_TOKEN, ITokenService } from '@delon/auth';
import { SettingsService } from '@delon/theme';
import { AuthnService } from '../../service/authn.service';
@Component({
selector: 'app-jwt-auth',
template: ``
})
export class JwtAuthComponent implements OnInit {
jwt = '';
constructor(
private authnService: AuthnService,
@Inject(ReuseTabService)
private reuseTabService: ReuseTabService,
private router: Router,
private settingsSrv: SettingsService,
private route: ActivatedRoute
) { }
ngOnInit(): void {
this.jwt = this.route.snapshot.queryParams['jwt'];
this.authnService.jwtAuth({ jwt: this.jwt }).subscribe(res => {
if (res.code !== 0) {
this.router.navigateByUrl('/passport/login');
} else {
// 清空路由复用信息
this.reuseTabService.clear();
// 设置用户Token信息
this.authnService.auth(res.data);
this.authnService.navigate({});
}
});
}
}
/*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
......@@ -21,6 +20,7 @@ import { RouterModule, Routes } from '@angular/router';
import { LayoutPassportComponent } from '../../layout/passport/passport.component';
import { CallbackComponent } from './callback.component';
import { ForgotComponent } from './forgot/forgot.component';
import { JwtAuthComponent } from './jwt-auth.component';
import { UserLockComponent } from './lock/lock.component';
import { UserLoginComponent } from './login/login.component';
import { UserRegisterResultComponent } from './register-result/register-result.component';
......@@ -60,7 +60,8 @@ const routes: Routes = [
]
},
// 单页不包裹Layout
{ path: 'passport/callback/:provider', component: CallbackComponent }
{ path: 'passport/callback/:provider', component: CallbackComponent },
{ path: 'passport/jwt/auth', component: JwtAuthComponent }
];
@NgModule({
......
......@@ -100,6 +100,18 @@ export class AuthnService {
this.tokenService.get()?.expired;
}
jwtAuth(authParam: any) {
return this.http.get(`/login/jwt/trust?_allow_anonymous=true`, authParam);
}
setInst(inst: any) {
localStorage.setItem(CONSTS.INST, JSON.stringify({ id: inst.id, name: inst.name, title: inst.frontTitle, logo: inst.logo }));
}
getInst() {
return JSON.parse(`${localStorage.getItem(CONSTS.INST)}`);
}
setRoles(aclService: ACLService | null): string[] {
let authorities: string[] = JSON.parse(localStorage.getItem(CONSTS.TOKEN) || '')?.authorities || [];
if (aclService) {
......
......@@ -15,6 +15,7 @@
*/
export const CONSTS = {
INST: 'inst',
CONGRESS: 'congress',
ONLINE_TICKET: 'online_ticket',
REDIRECT_URI: 'redirect_uri',
......
<div class="container">
<div nz-row style="border-bottom: 1px solid #e5e5e5; min-height: 60px; text-shadow: 0 1px 0 #fff">
<div nz-col nzMd="2"></div>
<div nz-col nzMd="2" style="text-align: right"> <img style="margin-top: 6px" class="logo" src="./assets/logo.jpg" /></div>
<div nz-col nzMd="2" style="text-align: right">
<img *ngIf="!isTitle" style="margin-top: 6px" class="logo" src="./assets/logo.jpg" />
<img *ngIf="isTitle" style="margin-top: 6px" class="logo" src="{{ inst.logo }}" />
</div>
<div nz-col nzMd="10">
<div class="title">{{ 'mxk.login.title' | i18n }}{{ 'mxk.title' | i18n }}</div>
<div *ngIf="!isTitle" class="title">Max<span style="color: #ffd700">Key</span>{{ 'mxk.title' | i18n }}</div>
<div *ngIf="isTitle" class="title">{{ inst.title }}</div>
</div>
<div nz-col nzMd="6"></div>
<div nz-col nzXs="0" nzSm="0" nzMd="2"><header-i18n showLangText="false" class="langs"></header-i18n></div>
<div nz-col nzXs="0" nzSm="0" nzMd="2">
<header-i18n showLangText="false" class="langs"></header-i18n>
</div>
<div nz-col nzMd="2"></div>
</div>
......@@ -19,10 +25,11 @@
<div style="margin-top: 20px">
MaxKey {{ version }}<br />
Copyright
<i nz-icon nzType="copyright"></i> 2022 <a href="//www.maxkey.top" target="_blank">http://www.maxkey.top</a><br />
<i nz-icon nzType="copyright"></i>
2022 <a href="//www.maxkey.top" target="_blank">http://www.maxkey.top</a><br />
Licensed under the Apache License, Version 2.0
</div>
</global-footer>
</div>
</div>
<theme-btn></theme-btn>
<theme-btn></theme-btn>
\ No newline at end of file
/*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, Inject, OnInit } from '@angular/core';
import { DA_SERVICE_TOKEN, ITokenService } from '@delon/auth';
import { AuthnService } from 'src/app/service/authn.service';
import { CONSTS } from 'src/app/shared/consts';
@Component({
......@@ -26,6 +26,8 @@ import { CONSTS } from 'src/app/shared/consts';
})
export class LayoutPassportComponent implements OnInit {
version = CONSTS.VERSION;
isTitle: boolean = false;
inst: any;
links = [
{
title: '帮助',
......@@ -37,9 +39,19 @@ export class LayoutPassportComponent implements OnInit {
}
];
constructor(@Inject(DA_SERVICE_TOKEN) private tokenService: ITokenService) { }
constructor(@Inject(DA_SERVICE_TOKEN) private tokenService: ITokenService, private authnService: AuthnService) { }
ngOnInit(): void {
if (
window.location.hostname != 'localhost' &&
window.location.hostname != 'sso.maxkey.top' &&
window.location.hostname != 'mgt.maxkey.top'
) {
this.inst = this.authnService.getInst();
if (this.inst != null) {
this.isTitle = true;
}
}
this.tokenService.clear();
}
}
/*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, ChangeDetectorRef, ViewContainerRef, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
......
/*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, ChangeDetectorRef, ViewContainerRef, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
......
/*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, ChangeDetectorRef, ViewContainerRef, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
......
/*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, ChangeDetectorRef, ViewContainerRef, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
......
/*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, ChangeDetectorRef, ViewContainerRef, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
......
/*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, ChangeDetectorRef, ViewContainerRef, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
......
/*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, ChangeDetectorRef, ViewContainerRef, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
......
/*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, ChangeDetectorRef, ViewContainerRef, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
......
......@@ -20,7 +20,7 @@ import { ReuseTabService } from '@delon/abc/reuse-tab';
import { DA_SERVICE_TOKEN, ITokenService } from '@delon/auth';
import { SettingsService } from '@delon/theme';
import { AuthenticationService } from '../../service/authentication.service';
import { AuthnService } from '../../service/authn.service';
@Component({
selector: 'app-jwt-auth',
......@@ -30,7 +30,7 @@ export class JwtAuthComponent implements OnInit {
jwt = '';
constructor(
private authenticationService: AuthenticationService,
private authnService: AuthnService,
@Inject(ReuseTabService)
private reuseTabService: ReuseTabService,
private router: Router,
......@@ -41,15 +41,15 @@ export class JwtAuthComponent implements OnInit {
ngOnInit(): void {
this.jwt = this.route.snapshot.queryParams['jwt'];
this.authenticationService.jwtAuth({ jwt: this.jwt }).subscribe(res => {
this.authnService.jwtAuth({ jwt: this.jwt }).subscribe(res => {
if (res.code !== 0) {
this.router.navigateByUrl('/passport/login');
} else {
// 清空路由复用信息
this.reuseTabService.clear();
// 设置用户Token信息
this.authenticationService.auth(res.data);
this.authenticationService.navigate({});
this.authnService.auth(res.data);
this.authnService.navigate({});
}
});
}
......
......@@ -25,7 +25,7 @@ import { environment } from '@env/environment';
import { NzTabChangeEvent } from 'ng-zorro-antd/tabs';
import { finalize } from 'rxjs/operators';
import { AuthenticationService } from '../../../service/authentication.service';
import { AuthnService } from '../../../service/authn.service';
import { ImageCaptchaService } from '../../../service/image-captcha.service';
@Component({
......@@ -37,16 +37,11 @@ import { ImageCaptchaService } from '../../../service/image-captcha.service';
export class UserLoginComponent implements OnInit, OnDestroy {
constructor(
fb: FormBuilder,
private router: Router,
private settingsService: SettingsService,
@Optional()
@Inject(ReuseTabService)
private reuseTabService: ReuseTabService,
@Inject(DA_SERVICE_TOKEN) private tokenService: ITokenService,
private startupSrv: StartupService,
private authenticationService: AuthenticationService,
private authnService: AuthnService,
private imageCaptchaService: ImageCaptchaService,
private http: _HttpClient,
private cdr: ChangeDetectorRef
) {
this.form = fb.group({
......@@ -84,8 +79,8 @@ export class UserLoginComponent implements OnInit, OnDestroy {
ngOnInit(): void {
//init socials,state
this.authenticationService.clear();
this.authenticationService
this.authnService.clear();
this.authnService
.get({})
.pipe(
finalize(() => {
......@@ -100,6 +95,7 @@ export class UserLoginComponent implements OnInit, OnDestroy {
} else {
// 清空路由复用信息
console.log(res.data);
this.authnService.setInst(res.data.inst);
this.state = res.data.state;
//init image captcha
this.imageCaptchaService.captcha({ state: this.state }).subscribe(res => {
......@@ -149,7 +145,7 @@ export class UserLoginComponent implements OnInit, OnDestroy {
// 然一般来说登录请求不需要校验,因此可以在请求URL加上:`/login?_allow_anonymous=true` 表示不触发用户 Token 校验
this.loading = true;
this.cdr.detectChanges();
this.authenticationService
this.authnService
.login({
authType: 'normal',
state: this.state,
......@@ -174,8 +170,8 @@ export class UserLoginComponent implements OnInit, OnDestroy {
// 清空路由复用信息
this.reuseTabService.clear();
// 设置用户Token信息
this.authenticationService.auth(res.data);
this.authenticationService.navigate({});
this.authnService.auth(res.data);
this.authnService.navigate({});
}
this.cdr.detectChanges();
});
......
......@@ -28,7 +28,7 @@ import { hostname } from 'os';
@Injectable({
providedIn: 'root'
})
export class AuthenticationService {
export class AuthnService {
redirect_uri: string = '';
constructor(
......@@ -94,6 +94,14 @@ export class AuthenticationService {
this.tokenService.get()?.expired;
}
setInst(inst: any) {
localStorage.setItem(CONSTS.INST, JSON.stringify({ id: inst.id, name: inst.name, title: inst.consoleTitle, logo: inst.logo }));
}
getInst() {
return JSON.parse(`${localStorage.getItem(CONSTS.INST)}`);
}
navigate(authJwt: any) {
// 重新获取 StartupService 内容,我们始终认为应用信息一般都会受当前用户授权范围而影响
this.startupService.load().subscribe(() => {
......
......@@ -16,6 +16,7 @@
export const CONSTS = {
CONGRESS: 'congress',
INST: 'inst',
REDIRECT_URI: 'redirect_uri',
REMEMBER: 'remember',
VERSION: 'v3.5.0 GA'
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册