This commit is contained in:
MaxKey 2022-04-30 19:37:08 +08:00
parent eb748ac827
commit 0f912df258
12 changed files with 153 additions and 53 deletions

View File

@ -25,14 +25,30 @@ import org.maxkey.authn.SignPrincipal;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import com.fasterxml.jackson.annotation.JsonProperty;
public class AuthJwt implements Serializable { public class AuthJwt implements Serializable {
private static final long serialVersionUID = -914373258878811144L; private static final long serialVersionUID = -914373258878811144L;
public static final String ACCESS_TOKEN = "access_token";
public static final String REFRESH_TOKEN = "refresh_token";
public static final String EXPIRES_IN = "expired";
private String ticket; private String ticket;
private String token;
private String refreshToken;
private String type = "Bearer"; private String type = "Bearer";
private String token;
@JsonProperty(REFRESH_TOKEN)
private String refreshToken;
@JsonProperty(EXPIRES_IN)
private int expiresIn;
private String remeberMe; private String remeberMe;
private String id; private String id;
private String name; private String name;
@ -44,27 +60,36 @@ public class AuthJwt implements Serializable {
private int passwordSetType; private int passwordSetType;
private List<String> authorities; private List<String> authorities;
public AuthJwt(String ticket, String type, String token, String refreshToken, int expiresIn, String remeberMe,
public AuthJwt(String token, String id, String username, String displayName, String email, String instId, String id, String name, String username, String displayName, String email, String instId, String instName,
String instName, List<String> authorities) { int passwordSetType, List<String> authorities) {
super();
this.ticket = ticket;
this.type = type;
this.token = token; this.token = token;
this.refreshToken = refreshToken;
this.expiresIn = expiresIn;
this.remeberMe = remeberMe;
this.id = id; this.id = id;
this.name = username; this.name = name;
this.username = username; this.username = username;
this.displayName = displayName; this.displayName = displayName;
this.email = email; this.email = email;
this.instId = instId; this.instId = instId;
this.instName = instName; this.instName = instName;
this.passwordSetType = passwordSetType;
this.authorities = authorities; this.authorities = authorities;
} }
public AuthJwt(String token,String refreshToken, Authentication authentication) {
public AuthJwt(String token, Authentication authentication,int expiresIn,String refreshToken) {
SignPrincipal principal = ((SignPrincipal)authentication.getPrincipal()); SignPrincipal principal = ((SignPrincipal)authentication.getPrincipal());
this.token = token; this.token = token;
this.expiresIn = expiresIn;
this.refreshToken = refreshToken; this.refreshToken = refreshToken;
this.ticket = principal.getSession().getId();
this.ticket = principal.getSession().getId();
this.id = principal.getUserInfo().getId(); this.id = principal.getUserInfo().getId();
this.username = principal.getUserInfo().getUsername(); this.username = principal.getUserInfo().getUsername();
this.name = this.username; this.name = this.username;
@ -176,6 +201,16 @@ public class AuthJwt implements Serializable {
this.refreshToken = refreshToken; this.refreshToken = refreshToken;
} }
public int getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(int expiresIn) {
this.expiresIn = expiresIn;
}
@Override @Override
public String toString() { public String toString() {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();

View File

@ -7,6 +7,7 @@ import org.joda.time.DateTime;
import org.maxkey.authn.SignPrincipal; import org.maxkey.authn.SignPrincipal;
import org.maxkey.crypto.jwt.HMAC512Service; import org.maxkey.crypto.jwt.HMAC512Service;
import org.maxkey.entity.UserInfo; import org.maxkey.entity.UserInfo;
import org.maxkey.util.StringUtils;
import org.maxkey.web.WebContext; import org.maxkey.web.WebContext;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -33,7 +34,7 @@ public class AuthJwtService {
DateTime currentDateTime = DateTime.now(); DateTime currentDateTime = DateTime.now();
String subject = principal.getUsername(); String subject = principal.getUsername();
Date expirationTime = currentDateTime.plusSeconds(expires).toDate(); Date expirationTime = currentDateTime.plusSeconds(expires).toDate();
_logger.debug("jwt subject : {} , expiration Time : {}" , subject,expirationTime); _logger.trace("jwt subject : {} , expiration Time : {}" , subject,expirationTime);
JWTClaimsSet jwtClaims =new JWTClaimsSet.Builder() JWTClaimsSet jwtClaims =new JWTClaimsSet.Builder()
.issuer(issuer) .issuer(issuer)
@ -102,12 +103,14 @@ public class AuthJwtService {
*/ */
public boolean validateJwtToken(String authToken) { public boolean validateJwtToken(String authToken) {
try { try {
if(StringUtils.isNotBlank(authToken)) {
JWTClaimsSet claims = resolve(authToken); JWTClaimsSet claims = resolve(authToken);
boolean isExpiration = claims.getExpirationTime().after(DateTime.now().toDate()); boolean isExpiration = claims.getExpirationTime().after(DateTime.now().toDate());
boolean isVerify = hmac512Service.verify(authToken); boolean isVerify = hmac512Service.verify(authToken);
_logger.debug("JWT Verify {} , now {} , ExpirationTime {} , isExpiration : {}" , _logger.trace("JWT Verify {} , now {} , ExpirationTime {} , isExpiration : {}" ,
isVerify,DateTime.now().toDate(),claims.getExpirationTime(),isExpiration); isVerify,DateTime.now().toDate(),claims.getExpirationTime(),isExpiration);
return isVerify && isExpiration; return isVerify && isExpiration;
}
} catch (ParseException e) { } catch (ParseException e) {
_logger.error("authToken {}",authToken); _logger.error("authToken {}",authToken);
_logger.error("ParseException ",e); _logger.error("ParseException ",e);

View File

@ -66,13 +66,22 @@ public class AuthTokenService extends AuthJwtService{
public AuthJwt genAuthJwt(Authentication authentication) { public AuthJwt genAuthJwt(Authentication authentication) {
if(authentication != null) { if(authentication != null) {
String refreshToken = refreshTokenService.genRefreshToken(authentication); String refreshToken = refreshTokenService.genRefreshToken(authentication);
return new AuthJwt(genJwt(authentication),refreshToken, authentication); String accessToken = genJwt(authentication);
AuthJwt authJwt = new AuthJwt(
accessToken,
authentication,
authJwkConfig.getExpires(),
refreshToken);
return authJwt;
} }
return null; return null;
} }
public String genJwt(Authentication authentication) { public String genJwt(Authentication authentication) {
return genJwt( authentication,authJwkConfig.getIssuer(),authJwkConfig.getExpires()); return genJwt(
authentication,
authJwkConfig.getIssuer(),
authJwkConfig.getExpires());
} }
@ -100,8 +109,9 @@ public class AuthTokenService extends AuthJwtService{
congress, congress,
new AuthJwt( new AuthJwt(
genJwt(authentication), genJwt(authentication),
refreshToken, authentication,
authentication) authJwkConfig.getExpires(),
refreshToken)
); );
return congress; return congress;
} }

View File

@ -37,18 +37,23 @@ import org.springframework.security.core.Authentication;
public class AuthorizationUtils { public class AuthorizationUtils {
private static final Logger _logger = LoggerFactory.getLogger(AuthorizationUtils.class); private static final Logger _logger = LoggerFactory.getLogger(AuthorizationUtils.class);
public static final String Authorization_Cookie = "congress"; public static final class BEARERTYPE{
public static final String CONGRESS = "congress";
public static final String AUTHORIZATION = "Authorization";
}
public static void authenticateWithCookie( public static void authenticateWithCookie(
HttpServletRequest request, HttpServletRequest request,
AuthTokenService authTokenService, AuthTokenService authTokenService,
SessionManager sessionManager SessionManager sessionManager
) throws ParseException{ ) throws ParseException{
Cookie authCookie = WebContext.getCookie(request, Authorization_Cookie); Cookie authCookie = WebContext.getCookie(request, BEARERTYPE.CONGRESS);
if(authCookie != null ) { if(authCookie != null ) {
String authorization = authCookie.getValue(); String authorization = authCookie.getValue();
doJwtAuthenticate(authorization,authTokenService,sessionManager); _logger.trace("Try congress authenticate .");
_logger.debug("congress automatic authenticated ."); doJwtAuthenticate(BEARERTYPE.CONGRESS,authorization,authTokenService,sessionManager);
} }
} }
@ -59,13 +64,14 @@ public class AuthorizationUtils {
) throws ParseException{ ) throws ParseException{
String authorization = AuthorizationHeaderUtils.resolveBearer(request); String authorization = AuthorizationHeaderUtils.resolveBearer(request);
if(authorization != null ) { if(authorization != null ) {
doJwtAuthenticate(authorization,authTokenService,sessionManager); _logger.trace("Try Authorization authenticate .");
_logger.debug("Authorization automatic authenticated ."); doJwtAuthenticate(BEARERTYPE.AUTHORIZATION,authorization,authTokenService,sessionManager);
} }
} }
public static void doJwtAuthenticate( public static void doJwtAuthenticate(
String bearerType,
String authorization, String authorization,
AuthTokenService authTokenService, AuthTokenService authTokenService,
SessionManager sessionManager) throws ParseException { SessionManager sessionManager) throws ParseException {
@ -75,12 +81,17 @@ public class AuthorizationUtils {
Session session = sessionManager.get(sessionId); Session session = sessionManager.get(sessionId);
if(session != null) { if(session != null) {
setAuthentication(session.getAuthentication()); setAuthentication(session.getAuthentication());
_logger.debug("{} Automatic authenticated .",bearerType);
}else { }else {
setAuthentication(null); //time out
_logger.debug("Session timeout .");
clearAuthentication();
} }
} }
}else { }else {
setAuthentication(null); //token invalidate
_logger.debug("Token invalidate .");
clearAuthentication();
} }
} }
@ -100,6 +111,10 @@ public class AuthorizationUtils {
WebContext.setAttribute(WebConstants.AUTHENTICATION, authentication); WebContext.setAttribute(WebConstants.AUTHENTICATION, authentication);
} }
public static void clearAuthentication() {
WebContext.removeAttribute(WebConstants.AUTHENTICATION);
}
public static boolean isAuthenticated() { public static boolean isAuthenticated() {
return getAuthentication() != null; return getAuthentication() != null;
} }

View File

@ -33,6 +33,7 @@ public class LoginRefreshPoint {
@RequestMapping(value={"/token/refresh"}, produces = {MediaType.APPLICATION_JSON_VALUE}) @RequestMapping(value={"/token/refresh"}, produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<?> refresh( public ResponseEntity<?> refresh(
@RequestHeader(name = "refresh_token", required = true) String refreshToken) { @RequestHeader(name = "refresh_token", required = true) String refreshToken) {
_logger.debug("try to refresh token " );
_logger.trace("refresh token {} " , refreshToken); _logger.trace("refresh token {} " , refreshToken);
try { try {
if(refreshTokenService.validateJwtToken(refreshToken)) { if(refreshTokenService.validateJwtToken(refreshToken)) {
@ -47,7 +48,7 @@ public class LoginRefreshPoint {
_logger.debug("Session is timeout , sessionId [{}]" , sessionId); _logger.debug("Session is timeout , sessionId [{}]" , sessionId);
} }
}else { }else {
_logger.trace("refresh token is not validate ."); _logger.debug("refresh token is not validate .");
} }
}catch(Exception e) { }catch(Exception e) {
_logger.error("Refresh Exception !",e); _logger.error("Refresh Exception !",e);

View File

@ -22,6 +22,7 @@ import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import org.maxkey.authn.annotation.CurrentUser; import org.maxkey.authn.annotation.CurrentUser;
import org.maxkey.authn.jwt.AuthTokenService;
import org.maxkey.authn.web.AuthorizationUtils; import org.maxkey.authn.web.AuthorizationUtils;
import org.maxkey.authz.oauth2.common.OAuth2Constants; import org.maxkey.authz.oauth2.common.OAuth2Constants;
import org.maxkey.authz.oauth2.provider.AuthorizationRequest; import org.maxkey.authz.oauth2.provider.AuthorizationRequest;
@ -81,6 +82,9 @@ public class OAuth20AccessConfirmationEndpoint {
@Autowired @Autowired
protected ApplicationConfig applicationConfig; protected ApplicationConfig applicationConfig;
@Autowired
AuthTokenService authTokenService;
/** /**
* getAccessConfirmation. * getAccessConfirmation.
* @param model Map * @param model Map
@ -95,7 +99,7 @@ public class OAuth20AccessConfirmationEndpoint {
AuthorizationRequest clientAuth = AuthorizationRequest clientAuth =
(AuthorizationRequest) momentaryService.get(currentUser.getSessionId(), "authorizationRequest"); (AuthorizationRequest) momentaryService.get(currentUser.getSessionId(), "authorizationRequest");
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId(),true); ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId(),true);
model.put("oauth_approval", WebContext.genId()); model.put("oauth_approval", authTokenService.genRandomJwt());
model.put("auth_request", clientAuth); model.put("auth_request", clientAuth);
model.put("client", client); model.put("client", client);
model.put("oauth_version", "oauth 2.0"); model.put("oauth_version", "oauth 2.0");
@ -136,7 +140,7 @@ public class OAuth20AccessConfirmationEndpoint {
@PathVariable("oauth_approval") String oauth_approval, @PathVariable("oauth_approval") String oauth_approval,
@CurrentUser UserInfo currentUser) { @CurrentUser UserInfo currentUser) {
Map<String, Object> model = new HashMap<String, Object>(); Map<String, Object> model = new HashMap<String, Object>();
if(StringUtils.isNotBlank(oauth_approval)) { if(authTokenService.validateJwtToken(oauth_approval)) {
try { try {
AuthorizationRequest clientAuth = AuthorizationRequest clientAuth =
(AuthorizationRequest) momentaryService.get(currentUser.getSessionId(), "authorizationRequest"); (AuthorizationRequest) momentaryService.get(currentUser.getSessionId(), "authorizationRequest");

View File

@ -45,6 +45,7 @@ export class DefaultInterceptor implements HttpInterceptor {
private refreshTokenEnabled = environment.api.refreshTokenEnabled; private refreshTokenEnabled = environment.api.refreshTokenEnabled;
private refreshTokenType: 're-request' | 'auth-refresh' = environment.api.refreshTokenType; private refreshTokenType: 're-request' | 'auth-refresh' = environment.api.refreshTokenType;
private refreshToking = false; private refreshToking = false;
private notified = false;
private refreshToken$: BehaviorSubject<any> = new BehaviorSubject<any>(null); private refreshToken$: BehaviorSubject<any> = new BehaviorSubject<any>(null);
constructor(private injector: Injector) { constructor(private injector: Injector) {
@ -70,7 +71,10 @@ export class DefaultInterceptor implements HttpInterceptor {
} }
private goTo(url: string): void { private goTo(url: string): void {
setTimeout(() => this.injector.get(Router).navigateByUrl(url)); setTimeout(() => {
this.injector.get(Router).navigateByUrl(url);
this.notified = false;
});
} }
private checkStatus(ev: HttpResponseBase): void { private checkStatus(ev: HttpResponseBase): void {
@ -87,7 +91,7 @@ export class DefaultInterceptor implements HttpInterceptor {
*/ */
private refreshTokenRequest(): Observable<any> { private refreshTokenRequest(): Observable<any> {
const model = this.tokenSrv.get(); const model = this.tokenSrv.get();
return this.http.post(`/auth/token/refresh`, null, null, { headers: { refresh_token: model?.['refreshToken'] || '' } }); return this.http.post(`/auth/token/refresh`, null, null, { headers: { refresh_token: model?.['refresh_token'] || '' } });
} }
// #region 刷新Token方式一使用 401 重新刷新 Token // #region 刷新Token方式一使用 401 重新刷新 Token
@ -117,7 +121,7 @@ export class DefaultInterceptor implements HttpInterceptor {
console.log(res.data); console.log(res.data);
// 通知后续请求继续执行 // 通知后续请求继续执行
this.refreshToking = false; this.refreshToking = false;
this.refreshToken$.next(res.data.refreshToken); this.refreshToken$.next(res.data.refresh_token);
this.cookieService.set(CONSTS.CONGRESS, res.data.token); this.cookieService.set(CONSTS.CONGRESS, res.data.token);
// 重新保存新 token // 重新保存新 token
this.tokenSrv.set(res.data); this.tokenSrv.set(res.data);
@ -181,9 +185,12 @@ export class DefaultInterceptor implements HttpInterceptor {
// #endregion // #endregion
private toLogin(): void { private toLogin(): void {
if (!this.notified) {
this.notified = true;
this.notification.error(`未登录或登录已过期,请重新登录。`, ``); this.notification.error(`未登录或登录已过期,请重新登录。`, ``);
this.goTo(this.tokenSrv.login_url!); this.goTo(this.tokenSrv.login_url!);
} }
}
private handleData(ev: HttpResponseBase, req: HttpRequest<any>, next: HttpHandler): Observable<any> { private handleData(ev: HttpResponseBase, req: HttpRequest<any>, next: HttpHandler): Observable<any> {
this.checkStatus(ev); this.checkStatus(ev);
@ -227,10 +234,7 @@ export class DefaultInterceptor implements HttpInterceptor {
break; break;
default: default:
if (ev instanceof HttpErrorResponse) { if (ev instanceof HttpErrorResponse) {
console.warn( console.warn('未可知错误大部分是由于后端不支持跨域CORS或无效配置引起.', ev);
'未可知错误大部分是由于后端不支持跨域CORS或无效配置引起请参考 https://ng-alain.com/docs/server 解决跨域问题',
ev
);
} }
break; break;
} }

View File

@ -78,7 +78,14 @@ import { LayoutDefaultOptions } from '../../theme/layout-default';
<router-outlet></router-outlet> <router-outlet></router-outlet>
</ng-template> </ng-template>
</layout-default> </layout-default>
<global-footer style="border-top: 1px solid #e5e5e5; min-height: 120px; text-shadow: 0 1px 0 #fff;margin:0;">
<div style="margin-top: 30px">
MaxKey v3.5.0 GA<br />
Copyright
<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>
<setting-drawer *ngIf="showSettingDrawer"></setting-drawer> <setting-drawer *ngIf="showSettingDrawer"></setting-drawer>
<theme-btn></theme-btn> <theme-btn></theme-btn>
` `

View File

@ -73,7 +73,7 @@ export class AuthenticationService {
} }
this.cookieService.set(CONSTS.CONGRESS, authJwt.token); this.cookieService.set(CONSTS.CONGRESS, authJwt.token);
this.cookieService.set(CONSTS.CONGRESS, authJwt.ticket, { domain: subHostName }); this.cookieService.set(CONSTS.ONLINE_TICKET, authJwt.ticket, { domain: subHostName });
if (authJwt.remeberMe) { if (authJwt.remeberMe) {
localStorage.setItem(CONSTS.REMEMBER, authJwt.remeberMe); localStorage.setItem(CONSTS.REMEMBER, authJwt.remeberMe);
} }

View File

@ -1,5 +1,6 @@
export const CONSTS = { export const CONSTS = {
CONGRESS: 'congress', CONGRESS: 'congress',
ONLINE_TICKET: 'online_ticket',
REDIRECT_URI: 'redirect_uri', REDIRECT_URI: 'redirect_uri',
REMEMBER: 'remember_me' REMEMBER: 'remember_me'
}; };

View File

@ -13,9 +13,12 @@ import { DA_SERVICE_TOKEN, ITokenService } from '@delon/auth';
import { ALAIN_I18N_TOKEN, _HttpClient } from '@delon/theme'; import { ALAIN_I18N_TOKEN, _HttpClient } from '@delon/theme';
import { environment } from '@env/environment'; import { environment } from '@env/environment';
import { NzNotificationService } from 'ng-zorro-antd/notification'; import { NzNotificationService } from 'ng-zorro-antd/notification';
import { CookieService } from 'ngx-cookie-service';
import { BehaviorSubject, Observable, of, throwError } from 'rxjs'; import { BehaviorSubject, Observable, of, throwError } from 'rxjs';
import { catchError, filter, mergeMap, switchMap, take } from 'rxjs/operators'; import { catchError, filter, mergeMap, switchMap, take } from 'rxjs/operators';
import { CONSTS } from '../../shared/consts';
const CODEMESSAGE: { [key: number]: string } = { const CODEMESSAGE: { [key: number]: string } = {
200: '服务器成功返回请求的数据。', 200: '服务器成功返回请求的数据。',
201: '新建或修改数据成功。', 201: '新建或修改数据成功。',
@ -42,6 +45,7 @@ export class DefaultInterceptor implements HttpInterceptor {
private refreshTokenEnabled = environment.api.refreshTokenEnabled; private refreshTokenEnabled = environment.api.refreshTokenEnabled;
private refreshTokenType: 're-request' | 'auth-refresh' = environment.api.refreshTokenType; private refreshTokenType: 're-request' | 'auth-refresh' = environment.api.refreshTokenType;
private refreshToking = false; private refreshToking = false;
private notified = false;
private refreshToken$: BehaviorSubject<any> = new BehaviorSubject<any>(null); private refreshToken$: BehaviorSubject<any> = new BehaviorSubject<any>(null);
constructor(private injector: Injector) { constructor(private injector: Injector) {
@ -54,6 +58,10 @@ export class DefaultInterceptor implements HttpInterceptor {
return this.injector.get(NzNotificationService); return this.injector.get(NzNotificationService);
} }
private get cookieService(): CookieService {
return this.injector.get(CookieService);
}
private get tokenSrv(): ITokenService { private get tokenSrv(): ITokenService {
return this.injector.get(DA_SERVICE_TOKEN); return this.injector.get(DA_SERVICE_TOKEN);
} }
@ -63,7 +71,10 @@ export class DefaultInterceptor implements HttpInterceptor {
} }
private goTo(url: string): void { private goTo(url: string): void {
setTimeout(() => this.injector.get(Router).navigateByUrl(url)); setTimeout(() => {
this.injector.get(Router).navigateByUrl(url);
this.notified = false;
});
} }
private checkStatus(ev: HttpResponseBase): void { private checkStatus(ev: HttpResponseBase): void {
@ -91,6 +102,7 @@ export class DefaultInterceptor implements HttpInterceptor {
this.toLogin(); this.toLogin();
return throwError(ev); return throwError(ev);
} }
// 2、如果 `refreshToking` 为 `true` 表示已经在请求刷新 Token 中,后续所有请求转入等待状态,直至结果返回后再重新发起请求 // 2、如果 `refreshToking` 为 `true` 表示已经在请求刷新 Token 中,后续所有请求转入等待状态,直至结果返回后再重新发起请求
if (this.refreshToking) { if (this.refreshToking) {
return this.refreshToken$.pipe( return this.refreshToken$.pipe(
@ -99,17 +111,20 @@ export class DefaultInterceptor implements HttpInterceptor {
switchMap(() => next.handle(this.reAttachToken(req))) switchMap(() => next.handle(this.reAttachToken(req)))
); );
} }
// 3、尝试调用刷新 Token // 3、尝试调用刷新 Token
this.refreshToking = true; this.refreshToking = true;
this.refreshToken$.next(null); this.refreshToken$.next(null);
return this.refreshTokenRequest().pipe( return this.refreshTokenRequest().pipe(
switchMap(res => { switchMap(res => {
console.log(res.data);
// 通知后续请求继续执行 // 通知后续请求继续执行
this.refreshToking = false; this.refreshToking = false;
this.refreshToken$.next(res); this.refreshToken$.next(res.data.refresh_token);
this.cookieService.set(CONSTS.CONGRESS, res.data.token);
// 重新保存新 token // 重新保存新 token
this.tokenSrv.set(res); this.tokenSrv.set(res.data);
// 重新发起请求 // 重新发起请求
return next.handle(this.reAttachToken(req)); return next.handle(this.reAttachToken(req));
}), }),
@ -127,11 +142,14 @@ export class DefaultInterceptor implements HttpInterceptor {
* > `@delon/auth` Token * > `@delon/auth` Token
*/ */
private reAttachToken(req: HttpRequest<any>): HttpRequest<any> { private reAttachToken(req: HttpRequest<any>): HttpRequest<any> {
//console.log('reAttachToken');
// 以下示例是以 NG-ALAIN 默认使用 `SimpleInterceptor` // 以下示例是以 NG-ALAIN 默认使用 `SimpleInterceptor`
const token = this.tokenSrv.get()?.token; const token = this.tokenSrv.get()?.token;
return req.clone({ return req.clone({
setHeaders: { setHeaders: {
Authorization: `Bearer ${token}` Authorization: `Bearer ${token}`,
hostname: window.location.hostname,
AuthServer: 'MaxKey'
} }
}); });
} }
@ -167,9 +185,12 @@ export class DefaultInterceptor implements HttpInterceptor {
// #endregion // #endregion
private toLogin(): void { private toLogin(): void {
if (!this.notified) {
this.notified = true;
this.notification.error(`未登录或登录已过期,请重新登录。`, ``); this.notification.error(`未登录或登录已过期,请重新登录。`, ``);
this.goTo(this.tokenSrv.login_url!); this.goTo(this.tokenSrv.login_url!);
} }
}
private handleData(ev: HttpResponseBase, req: HttpRequest<any>, next: HttpHandler): Observable<any> { private handleData(ev: HttpResponseBase, req: HttpRequest<any>, next: HttpHandler): Observable<any> {
this.checkStatus(ev); this.checkStatus(ev);
@ -213,10 +234,7 @@ export class DefaultInterceptor implements HttpInterceptor {
break; break;
default: default:
if (ev instanceof HttpErrorResponse) { if (ev instanceof HttpErrorResponse) {
console.warn( console.warn('未可知错误大部分是由于后端不支持跨域CORS或无效配置引起.', ev);
'未可知错误大部分是由于后端不支持跨域CORS或无效配置引起请参考 https://ng-alain.com/docs/server 解决跨域问题',
ev
);
} }
break; break;
} }
@ -237,6 +255,8 @@ export class DefaultInterceptor implements HttpInterceptor {
if (jwtAuthn !== null) { if (jwtAuthn !== null) {
res['Authorization'] = `Bearer ${jwtAuthn.token}`; res['Authorization'] = `Bearer ${jwtAuthn.token}`;
} }
res['hostname'] = window.location.hostname;
res['AuthServer'] = 'MaxKey';
return res; return res;
} }

View File

@ -55,7 +55,7 @@ maxkey.app.issuer =CN=ConSec,CN=COM,CN=SH
maxkey.session.timeout =${SERVER_SESSION_TIMEOUT:1800} maxkey.session.timeout =${SERVER_SESSION_TIMEOUT:1800}
maxkey.auth.jwt.issuer =${maxkey.server.uri} maxkey.auth.jwt.issuer =${maxkey.server.uri}
maxkey.auth.jwt.expires =60 maxkey.auth.jwt.expires =600
maxkey.auth.jwt.secret =7heM-14BtxjyKPuH3ITIm7q2-ps5MuBirWCsrrdbzzSAOuSPrbQYiaJ54AeA0uH2XdkYy3hHAkTFIsieGkyqxOJZ_dQzrCbaYISH9rhUZAKYx8tUY0wkE4ArOC6LqHDJarR6UIcMsARakK9U4dhoOPO1cj74XytemI-w6ACYfzRUn_Rn4e-CQMcnD1C56oNEukwalf06xVgXl41h6K8IBEzLVod58y_VfvFn-NGWpNG0fy_Qxng6dg8Dgva2DobvzMN2eejHGLGB-x809MvC4zbG7CKNVlcrzMYDt2Gt2sOVDrt2l9YqJNfgaLFjrOEVw5cuXemGkX1MvHj6TAsbLg maxkey.auth.jwt.secret =7heM-14BtxjyKPuH3ITIm7q2-ps5MuBirWCsrrdbzzSAOuSPrbQYiaJ54AeA0uH2XdkYy3hHAkTFIsieGkyqxOJZ_dQzrCbaYISH9rhUZAKYx8tUY0wkE4ArOC6LqHDJarR6UIcMsARakK9U4dhoOPO1cj74XytemI-w6ACYfzRUn_Rn4e-CQMcnD1C56oNEukwalf06xVgXl41h6K8IBEzLVod58y_VfvFn-NGWpNG0fy_Qxng6dg8Dgva2DobvzMN2eejHGLGB-x809MvC4zbG7CKNVlcrzMYDt2Gt2sOVDrt2l9YqJNfgaLFjrOEVw5cuXemGkX1MvHj6TAsbLg
maxkey.auth.jwt.refresh.secret =7heM-14BtxjyKPuH3ITIm7q2-ps5MuBirWCsrrdbzzSAOuSPrbQYiaJ54AeA0uH2XdkYy3hHAkTFIsieGkyqxOJZ_dQzrCbaYISH9rhUZAKYx8tUY0wkE4ArOC6LqHDJarR6UIcMsARakK9U4dhoOPO1cj74XytemI-w6ACYfzRUn_Rn4e-CQMcnD1C56oNEukwalf06xVgXl41h6K8IBEzLVod58y_VfvFn-NGWpNG0fy_Qxng6dg8Dgva2DobvzMN2eejHGLGB-x809MvC4zbG7CKNVlcrzMYDt2Gt2sOVDrt2l9YqJNfgaLFjrOEVw5cuXemGkX1MvHj6TAsbLg maxkey.auth.jwt.refresh.secret =7heM-14BtxjyKPuH3ITIm7q2-ps5MuBirWCsrrdbzzSAOuSPrbQYiaJ54AeA0uH2XdkYy3hHAkTFIsieGkyqxOJZ_dQzrCbaYISH9rhUZAKYx8tUY0wkE4ArOC6LqHDJarR6UIcMsARakK9U4dhoOPO1cj74XytemI-w6ACYfzRUn_Rn4e-CQMcnD1C56oNEukwalf06xVgXl41h6K8IBEzLVod58y_VfvFn-NGWpNG0fy_Qxng6dg8Dgva2DobvzMN2eejHGLGB-x809MvC4zbG7CKNVlcrzMYDt2Gt2sOVDrt2l9YqJNfgaLFjrOEVw5cuXemGkX1MvHj6TAsbLg
############################################################################ ############################################################################