mirror of
https://gitee.com/dromara/MaxKey.git
synced 2025-12-08 09:58:56 +08:00
CONGRESS
This commit is contained in:
parent
eb748ac827
commit
0f912df258
@ -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();
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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");
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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>
|
||||||
`
|
`
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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'
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
############################################################################
|
############################################################################
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user