提交 48600c4a 编写于 作者: M MaxKey

jwt

上级 daad22a0
...@@ -45,7 +45,9 @@ setEnvVars.bat ...@@ -45,7 +45,9 @@ setEnvVars.bat
maxkey-web-frontend/maxkey-web-mgt-app/node_modules/ maxkey-web-frontend/maxkey-web-mgt-app/node_modules/
maxkey-web-frontend/maxkey-web-mgt-app/.angular maxkey-web-frontend/maxkey-web-mgt-app/.angular
maxkey-web-frontend/maxkey-web-mgt-app/yarn.lock maxkey-web-frontend/maxkey-web-mgt-app/yarn.lock
maxkey-web-frontend/maxkey-web-mgt-app/dist
maxkey-web-frontend/maxkey-web-app/node_modules/ maxkey-web-frontend/maxkey-web-app/node_modules/
maxkey-web-frontend/maxkey-web-app/.angular/ maxkey-web-frontend/maxkey-web-app/.angular/
maxkey-web-frontend/maxkey-web-app/yarn.lock maxkey-web-frontend/maxkey-web-app/yarn.lock
\ No newline at end of file maxkey-web-frontend/maxkey-web-app/dist
\ No newline at end of file
/* /*
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top] * Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -14,103 +14,68 @@ ...@@ -14,103 +14,68 @@
* limitations under the License. * limitations under the License.
*/ */
package org.maxkey.authn.support.jwt; package org.maxkey.authn.support.jwt;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.maxkey.authn.AbstractAuthenticationProvider; import org.maxkey.authn.AbstractAuthenticationProvider;
import org.maxkey.authn.LoginCredential; import org.maxkey.authn.LoginCredential;
import org.maxkey.authn.web.AuthorizationUtils; import org.maxkey.authn.jwt.AuthJwt;
import org.maxkey.authn.jwt.AuthTokenService;
import org.maxkey.configuration.ApplicationConfig; import org.maxkey.configuration.ApplicationConfig;
import org.maxkey.constants.ConstsLoginType; import org.maxkey.constants.ConstsLoginType;
import org.maxkey.entity.Message;
import org.maxkey.web.WebConstants; import org.maxkey.web.WebConstants;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.AsyncHandlerInterceptor; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.nimbusds.jwt.SignedJWT; import com.nimbusds.jwt.SignedJWT;
public class HttpJwtEntryPoint implements AsyncHandlerInterceptor { @Controller
@RequestMapping(value = "/login")
public class HttpJwtEntryPoint {
private static final Logger _logger = LoggerFactory.getLogger(HttpJwtEntryPoint.class); private static final Logger _logger = LoggerFactory.getLogger(HttpJwtEntryPoint.class);
boolean enable;
@Autowired
ApplicationConfig applicationConfig; ApplicationConfig applicationConfig;
@Autowired
AbstractAuthenticationProvider authenticationProvider ; AbstractAuthenticationProvider authenticationProvider ;
@Autowired
AuthTokenService authTokenService;
@Autowired
JwtLoginService jwtLoginService; JwtLoginService jwtLoginService;
@Override @RequestMapping(value={"/jwt"}, produces = {MediaType.APPLICATION_JSON_VALUE})
public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception { public ResponseEntity<?> jwt(@RequestParam(value = WebConstants.JWT_TOKEN_PARAMETER, required = false) String jwt) {
boolean isAuthenticated= AuthorizationUtils.isAuthenticated(); try {
String jwt = request.getParameter(WebConstants.JWT_TOKEN_PARAMETER); //for jwt Login
_logger.debug("jwt : " + jwt);
if(!enable
|| isAuthenticated SignedJWT signedJWT = jwtLoginService.jwtTokenValidation(jwt);
|| jwt == null){
return true; if(signedJWT != null) {
} String username =signedJWT.getJWTClaimsSet().getSubject();
LoginCredential loginCredential =new LoginCredential(username,"",ConstsLoginType.JWT);
_logger.debug("JWT Login Start ..."); Authentication authentication = authenticationProvider.authenticate(loginCredential,true);
_logger.trace("Request url : "+ request.getRequestURL()); _logger.debug("JWT Logined in , username " + username);
_logger.trace("Request URI : "+ request.getRequestURI()); AuthJwt authJwt = authTokenService.genAuthJwt(authentication);
_logger.trace("Request ContextPath : "+ request.getContextPath()); return new Message<AuthJwt>(authJwt).buildResponse();
_logger.trace("Request ServletPath : "+ request.getServletPath()); }
_logger.trace("RequestSessionId : "+ request.getRequestedSessionId()); }catch(Exception e) {
_logger.trace("isRequestedSessionIdValid : "+ request.isRequestedSessionIdValid()); _logger.error("Exception ",e);
_logger.trace("getSession : "+ request.getSession(false)); }
// session not exists,session timeout,recreate new session
if(request.getSession(false) == null) {
_logger.trace("recreate new session .");
request.getSession(true);
}
_logger.trace("getSession.getId : "+ request.getSession().getId());
//for jwt Login
_logger.debug("jwt : " + jwt);
SignedJWT signedJWT = jwtLoginService.jwtTokenValidation(jwt);
if(signedJWT != null) {
String username =signedJWT.getJWTClaimsSet().getSubject();
LoginCredential loginCredential =new LoginCredential(username,"",ConstsLoginType.JWT);
authenticationProvider.authenticate(loginCredential,true);
_logger.debug("JWT Logined in , username " + username);
}
return true; return new Message<AuthJwt>(Message.FAIL).buildResponse();
} }
public HttpJwtEntryPoint() {
super();
}
public HttpJwtEntryPoint (boolean enable) {
super();
this.enable = enable;
}
public HttpJwtEntryPoint(AbstractAuthenticationProvider authenticationProvider, JwtLoginService jwtLoginService,
ApplicationConfig applicationConfig, boolean enable) {
super();
this.authenticationProvider = authenticationProvider;
this.jwtLoginService = jwtLoginService;
this.applicationConfig = applicationConfig;
this.enable = enable;
}
public boolean isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
public void setApplicationConfig(ApplicationConfig applicationConfig) { public void setApplicationConfig(ApplicationConfig applicationConfig) {
this.applicationConfig = applicationConfig; this.applicationConfig = applicationConfig;
......
...@@ -34,7 +34,6 @@ import org.maxkey.web.WebContext; ...@@ -34,7 +34,6 @@ import org.maxkey.web.WebContext;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
/** /**
...@@ -61,8 +60,8 @@ public class AuthorizeBaseEndpoint { ...@@ -61,8 +60,8 @@ public class AuthorizeBaseEndpoint {
//session中为空或者id不一致重新加载 //session中为空或者id不一致重新加载
if(app == null || !app.getId().equalsIgnoreCase(id)) { if(app == null || !app.getId().equalsIgnoreCase(id)) {
app = appsService.get(id,true); app = appsService.get(id,true);
WebContext.setAttribute(WebConstants.AUTHORIZE_SIGN_ON_APP, app);
} }
WebContext.setAttribute(WebConstants.AUTHORIZE_SIGN_ON_APP, app);
} }
if(app == null){ if(app == null){
_logger.error("Applications id " + id + " is not exist."); _logger.error("Applications id " + id + " is not exist.");
......
...@@ -169,6 +169,8 @@ public class JwtAdapter extends AbstractAuthorizeAdapter { ...@@ -169,6 +169,8 @@ public class JwtAdapter extends AbstractAuthorizeAdapter {
modelAndView.addObject("token",serialize()); modelAndView.addObject("token",serialize());
modelAndView.addObject("jwtName",jwtDetails.getJwtName()); modelAndView.addObject("jwtName",jwtDetails.getJwtName());
modelAndView.addObject("tokenType",jwtDetails.getTokenType().toLowerCase());
return modelAndView; return modelAndView;
} }
......
...@@ -83,7 +83,7 @@ public class JwtAuthorizeEndpoint extends AuthorizeBaseEndpoint{ ...@@ -83,7 +83,7 @@ public class JwtAuthorizeEndpoint extends AuthorizeBaseEndpoint{
@CurrentUser UserInfo currentUser){ @CurrentUser UserInfo currentUser){
ModelAndView modelAndView=new ModelAndView(); ModelAndView modelAndView=new ModelAndView();
Apps application = getApp(id); Apps application = getApp(id);
AppsJwtDetails jwtDetails = jwtDetailsService.getAppDetails(id , true); AppsJwtDetails jwtDetails = jwtDetailsService.getAppDetails(application.getId() , true);
_logger.debug(""+jwtDetails); _logger.debug(""+jwtDetails);
jwtDetails.setAdapter(application.getAdapter()); jwtDetails.setAdapter(application.getAdapter());
jwtDetails.setIsAdapter(application.getIsAdapter()); jwtDetails.setIsAdapter(application.getIsAdapter());
...@@ -110,34 +110,7 @@ public class JwtAuthorizeEndpoint extends AuthorizeBaseEndpoint{ ...@@ -110,34 +110,7 @@ public class JwtAuthorizeEndpoint extends AuthorizeBaseEndpoint{
//encrypt //encrypt
adapter.encrypt(null, jwtDetails.getAlgorithmKey(), jwtDetails.getAlgorithm()); adapter.encrypt(null, jwtDetails.getAlgorithmKey(), jwtDetails.getAlgorithm());
if(jwtDetails.getTokenType().equalsIgnoreCase("POST")) { return adapter.authorize(modelAndView);
return adapter.authorize(modelAndView);
}else {
_logger.debug("Cookie Name : {}" , jwtDetails.getJwtName());
Cookie cookie= new Cookie(jwtDetails.getJwtName(),adapter.serialize());
Integer maxAge = jwtDetails.getExpires();
_logger.debug("Cookie Max Age : {} seconds." , maxAge);
cookie.setMaxAge(maxAge);
cookie.setPath("/");
//
//cookie.setDomain("."+applicationConfig.getBaseDomainName());
//tomcat 8.5
cookie.setDomain(applicationConfig.getBaseDomainName());
_logger.debug("Sub Domain Name : .{}",applicationConfig.getBaseDomainName());
response.addCookie(cookie);
if(jwtDetails.getRedirectUri().indexOf(applicationConfig.getBaseDomainName())>-1){
return WebContext.redirect(jwtDetails.getRedirectUri());
}else{
_logger.error(jwtDetails.getRedirectUri()+" not in domain "+applicationConfig.getBaseDomainName());
return null;
}
}
} }
@Operation(summary = "JWT JWK元数据接口", description = "参数mxk_metadata_APPID",method="GET") @Operation(summary = "JWT JWK元数据接口", description = "参数mxk_metadata_APPID",method="GET")
......
...@@ -129,6 +129,7 @@ public class OAuth20AccessConfirmationEndpoint { ...@@ -129,6 +129,7 @@ public class OAuth20AccessConfirmationEndpoint {
for (Object key : model.keySet()) { for (Object key : model.keySet()) {
_logger.trace("key " + key +"=" + model.get(key)); _logger.trace("key " + key +"=" + model.get(key));
} }
model.put("authorizeApproveUri", applicationConfig.getFrontendUri()+"/#/authz/oauth2approve"); model.put("authorizeApproveUri", applicationConfig.getFrontendUri()+"/#/authz/oauth2approve");
modelAndView.addObject("model", model); modelAndView.addObject("model", model);
......
...@@ -102,7 +102,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; ...@@ -102,7 +102,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
public class AuthorizationEndpoint extends AbstractEndpoint { public class AuthorizationEndpoint extends AbstractEndpoint {
final static Logger _logger = LoggerFactory.getLogger(AuthorizationEndpoint.class); final static Logger _logger = LoggerFactory.getLogger(AuthorizationEndpoint.class);
private static final String OAUTH_V20_AUTHORIZATION_URL = "%s" + OAuth2Constants.ENDPOINT.ENDPOINT_AUTHORIZE + "?client_id=%s&response_type=code&redirect_uri=%s&approval_prompt=auto"; private static final String OAUTH_V20_AUTHORIZATION_URL = "" + OAuth2Constants.ENDPOINT.ENDPOINT_AUTHORIZE + "?client_id=%s&response_type=code&redirect_uri=%s&approval_prompt=auto";
private RedirectResolver redirectResolver = new DefaultRedirectResolver(); private RedirectResolver redirectResolver = new DefaultRedirectResolver();
...@@ -132,7 +132,6 @@ public class AuthorizationEndpoint extends AbstractEndpoint { ...@@ -132,7 +132,6 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
String authorizationUrl = ""; String authorizationUrl = "";
try { try {
authorizationUrl = String.format(OAUTH_V20_AUTHORIZATION_URL, authorizationUrl = String.format(OAUTH_V20_AUTHORIZATION_URL,
applicationConfig.getServerPrefix(),
clientDetails.getClientId(), clientDetails.getClientId(),
HttpEncoder.encode(clientDetails.getRegisteredRedirectUri().toArray()[0].toString()) HttpEncoder.encode(clientDetails.getRegisteredRedirectUri().toArray()[0].toString())
); );
......
...@@ -38,7 +38,7 @@ import { LayoutDefaultOptions } from '../../theme/layout-default'; ...@@ -38,7 +38,7 @@ import { LayoutDefaultOptions } from '../../theme/layout-default';
<layout-default [options]="options" [asideUser]="asideUserTpl" [content]="contentTpl" [customError]="null"> <layout-default [options]="options" [asideUser]="asideUserTpl" [content]="contentTpl" [customError]="null">
<layout-default-header-item direction="left"> <layout-default-header-item direction="left">
<a href="#"> <a href="#">
<img src="../assets/logo.jpg" alt="logo" style="height: 50px;height: 50px;float: left;" /> <img src="./assets/logo.jpg" alt="logo" style="height: 50px;height: 50px;float: left;" />
<div class="alain-default__header-title"> Max<span style="color: #FFD700;">Key</span>{{ 'mxk.title' | i18n }} </div> <div class="alain-default__header-title"> Max<span style="color: #FFD700;">Key</span>{{ 'mxk.title' | i18n }} </div>
</a> </a>
</layout-default-header-item> </layout-default-header-item>
......
/* /*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top] * Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { Environment } from '@delon/theme'; import { Environment } from '@delon/theme';
...@@ -21,8 +20,8 @@ export const environment = { ...@@ -21,8 +20,8 @@ export const environment = {
production: true, production: true,
useHash: true, useHash: true,
api: { api: {
baseUrl: './', baseUrl: '/sign',
refreshTokenEnabled: true, refreshTokenEnabled: true,
refreshTokenType: 'auth-refresh' refreshTokenType: 're-request'
} }
} as Environment; } as Environment;
...@@ -27,7 +27,7 @@ export const environment = { ...@@ -27,7 +27,7 @@ export const environment = {
production: false, production: false,
useHash: true, useHash: true,
api: { api: {
baseUrl: 'http://sso.maxkey.top:8080/maxkey', baseUrl: 'http://sso.maxkey.top:9527/sign',
refreshTokenEnabled: true, refreshTokenEnabled: true,
refreshTokenType: 're-request' refreshTokenType: 're-request'
}, },
......
FROM node:16.14.2
LABEL authors="MaxKey <maxkeysupport@163.com>"
WORKDIR /usr/src/app
COPY package.json package.json
RUN npm config set registry https://registry.npm.taobao.org \
&& npm i
COPY ./src ./src
RUN npm install -g @angular/cli
RUN ng build --prod
FROM nginx
COPY ./nginx.conf /etc/nginx/conf.d/
RUN rm -rf /usr/share/nginx/html/*
COPY dist /usr/share/nginx/html
#CMD ["nginx", "-g", "daemon off;"]
#MaxKey mgmt server
server {
listen 9524;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
\ No newline at end of file
/* /*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top] * Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { import {
HttpErrorResponse, HttpErrorResponse,
......
...@@ -35,7 +35,7 @@ import { LayoutDefaultOptions } from '../../theme/layout-default'; ...@@ -35,7 +35,7 @@ import { LayoutDefaultOptions } from '../../theme/layout-default';
<layout-default [options]="options" [asideUser]="asideUserTpl" [content]="contentTpl" [customError]="null"> <layout-default [options]="options" [asideUser]="asideUserTpl" [content]="contentTpl" [customError]="null">
<layout-default-header-item direction="left"> <layout-default-header-item direction="left">
<a href="#"> <a href="#">
<img src="../assets/logo.jpg" alt="logo" style="height: 50px;height: 50px;float: left;" /> <img src="./assets/logo.jpg" alt="logo" style="height: 50px;height: 50px;float: left;" />
<div <div
class="alain-default__nav-item_title" class="alain-default__nav-item_title"
style="letter-spacing: 2px; style="letter-spacing: 2px;
......
/* /*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top] * Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
...@@ -28,7 +27,7 @@ import { SettingsService } from '@delon/theme'; ...@@ -28,7 +27,7 @@ import { SettingsService } from '@delon/theme';
export class CallbackComponent implements OnInit { export class CallbackComponent implements OnInit {
type = ''; type = '';
constructor(private socialService: SocialService, private settingsSrv: SettingsService, private route: ActivatedRoute) {} constructor(private socialService: SocialService, private settingsSrv: SettingsService, private route: ActivatedRoute) { }
ngOnInit(): void { ngOnInit(): void {
this.type = this.route.snapshot.params['type']; this.type = this.route.snapshot.params['type'];
......
/*
* 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 { AuthenticationService } from '../../service/authentication.service';
@Component({
selector: 'app-jwt-auth',
template: ``
})
export class JwtAuthComponent implements OnInit {
jwt = '';
constructor(
private authenticationService: AuthenticationService,
@Inject(ReuseTabService)
private reuseTabService: ReuseTabService,
private router: Router,
private settingsSrv: SettingsService,
private route: ActivatedRoute
) { }
ngOnInit(): void {
this.jwt = this.route.snapshot.queryParams['jwt'];
this.authenticationService.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({});
}
});
}
}
/* /*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top] * Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, Inject, OnDestroy, Optional } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, Inject, OnDestroy, Optional } from '@angular/core';
import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms'; import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
......
/* /*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top] * Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { LayoutPassportComponent } from '../../layout/passport/passport.component'; import { LayoutPassportComponent } from '../../layout/passport/passport.component';
import { CallbackComponent } from './callback.component'; import { CallbackComponent } from './callback.component';
import { JwtAuthComponent } from './jwt-auth.component';
import { UserLockComponent } from './lock/lock.component'; import { UserLockComponent } from './lock/lock.component';
import { UserLoginComponent } from './login/login.component'; import { UserLoginComponent } from './login/login.component';
import { UserRegisterResultComponent } from './register-result/register-result.component'; import { UserRegisterResultComponent } from './register-result/register-result.component';
...@@ -54,11 +54,11 @@ const routes: Routes = [ ...@@ -54,11 +54,11 @@ const routes: Routes = [
] ]
}, },
// 单页不包裹Layout // 单页不包裹Layout
{ path: 'passport/callback/:type', component: CallbackComponent } { path: 'passport/jwt/auth', component: JwtAuthComponent }
]; ];
@NgModule({ @NgModule({
imports: [RouterModule.forChild(routes)], imports: [RouterModule.forChild(routes)],
exports: [RouterModule] exports: [RouterModule]
}) })
export class PassportRoutingModule {} export class PassportRoutingModule { }
/* /*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top] * Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { SharedModule } from '@shared'; import { SharedModule } from '@shared';
...@@ -31,4 +30,4 @@ const COMPONENTS = [UserLoginComponent, UserRegisterResultComponent, UserRegiste ...@@ -31,4 +30,4 @@ const COMPONENTS = [UserLoginComponent, UserRegisterResultComponent, UserRegiste
imports: [SharedModule, PassportRoutingModule], imports: [SharedModule, PassportRoutingModule],
declarations: [...COMPONENTS] declarations: [...COMPONENTS]
}) })
export class PassportModule {} export class PassportModule { }
/* /*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top] * Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { Injectable, Inject } from '@angular/core'; import { Injectable, Inject } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
...@@ -62,6 +61,10 @@ export class AuthenticationService { ...@@ -62,6 +61,10 @@ export class AuthenticationService {
return this.http.post('/login/congress?_allow_anonymous=true', authParam); return this.http.post('/login/congress?_allow_anonymous=true', authParam);
} }
jwtAuth(authParam: any) {
return this.http.get(`/login/jwt?_allow_anonymous=true`, authParam);
}
clear() { clear() {
this.tokenService.clear(); this.tokenService.clear();
} }
......
/* /*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top] * Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { Environment } from '@delon/theme'; import { Environment } from '@delon/theme';
...@@ -21,8 +20,8 @@ export const environment = { ...@@ -21,8 +20,8 @@ export const environment = {
production: true, production: true,
useHash: true, useHash: true,
api: { api: {
baseUrl: './', baseUrl: '/maxkey-mgt-api',
refreshTokenEnabled: true, refreshTokenEnabled: true,
refreshTokenType: 'auth-refresh' refreshTokenType: 're-request'
} }
} as Environment; } as Environment;
/* /*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top] * Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
// This file can be replaced during build by using the `fileReplacements` array. // This file can be replaced during build by using the `fileReplacements` array.
// `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`. // `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`.
...@@ -28,7 +27,7 @@ export const environment = { ...@@ -28,7 +27,7 @@ export const environment = {
production: false, production: false,
useHash: true, useHash: true,
api: { api: {
baseUrl: 'http://sso.maxkey.top:9527/maxkey-mgt/', baseUrl: 'http://sso.maxkey.top:9526/maxkey-mgt-api/',
refreshTokenEnabled: true, refreshTokenEnabled: true,
refreshTokenType: 're-request' refreshTokenType: 're-request'
}, },
......
...@@ -54,8 +54,18 @@ public class HistorySignOnAppInterceptor implements AsyncHandlerInterceptor { ...@@ -54,8 +54,18 @@ public class HistorySignOnAppInterceptor implements AsyncHandlerInterceptor {
public boolean preHandle(HttpServletRequest request, public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) HttpServletResponse response, Object handler)
throws Exception { throws Exception {
_logger.debug("preHandle"); _logger.debug("preHandle {}",request.getRequestURI());
final Apps app = (Apps)WebContext.getAttribute(WebConstants.AUTHORIZE_SIGN_ON_APP); Apps app = (Apps)WebContext.getAttribute(WebConstants.AUTHORIZE_SIGN_ON_APP);
if(app == null) {
String appId ="";
//JWT
if(request.getRequestURI().contains("/authz/jwt/")) {
String [] requestURI = request.getRequestURI().split("/");
appId = requestURI[requestURI.length -1];
}
_logger.debug("appId {}",appId);
app = appsService.get(appId,true);
}
SignPrincipal principal = AuthorizationUtils.getPrincipal(); SignPrincipal principal = AuthorizationUtils.getPrincipal();
if(principal != null && app !=null) { if(principal != null && app !=null) {
if(principal.getGrantedAuthorityApps().contains(new SimpleGrantedAuthority(app.getId()))) { if(principal.getGrantedAuthorityApps().contains(new SimpleGrantedAuthority(app.getId()))) {
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#spring.profiles.active=http # #spring.profiles.active=http #
############################################################################ ############################################################################
#server port #server port
server.port =${SERVER_PORT:8080} server.port =${SERVER_PORT:9527}
#session default 600 #session default 600
#600s =10m #600s =10m
#1800s =30m #1800s =30m
...@@ -24,7 +24,7 @@ server.port =${SERVER_PORT:8080} ...@@ -24,7 +24,7 @@ server.port =${SERVER_PORT:8080}
#28800s =8h #28800s =8h
server.servlet.session.timeout =${SERVLET_SESSION_TIMEOUT:600} server.servlet.session.timeout =${SERVLET_SESSION_TIMEOUT:600}
#server context path #server context path
server.servlet.context-path =/maxkey server.servlet.context-path =/sign
#nacos discovery #nacos discovery
spring.cloud.nacos.discovery.enabled =${NACOS_DISCOVERY_ENABLED:false} spring.cloud.nacos.discovery.enabled =${NACOS_DISCOVERY_ENABLED:false}
spring.cloud.nacos.discovery.instance-enabled =false spring.cloud.nacos.discovery.instance-enabled =false
...@@ -44,7 +44,7 @@ maxkey.server.mgt.uri =${maxkey.server.name}:9527/maxk ...@@ -44,7 +44,7 @@ maxkey.server.mgt.uri =${maxkey.server.name}:9527/maxk
maxkey.server.authz.uri =${maxkey.server.name}:${server.port}${server.servlet.context-path} maxkey.server.authz.uri =${maxkey.server.name}:${server.port}${server.servlet.context-path}
#http://sso.maxkey.top/sign #http://sso.maxkey.top/sign
#http://sso.maxkey.top:4200 #http://sso.maxkey.top:4200
maxkey.server.frontend.uri =${maxkey.server.name}:${server.frontend.port} maxkey.server.frontend.uri =/maxkey
#InMemory 0 , Redis 2 #InMemory 0 , Redis 2
maxkey.server.persistence =${SERVER_PERSISTENCE:0} maxkey.server.persistence =${SERVER_PERSISTENCE:0}
#identity none, Kafka ,RocketMQ #identity none, Kafka ,RocketMQ
......
...@@ -7,17 +7,30 @@ ...@@ -7,17 +7,30 @@
</head> </head>
<body onload="document.forms[0].submit()" style="display:none"> <body onload="document.forms[0].submit()" style="display:none">
<form id="jwt_sso_form" name="jwt_sso_form" action="${action}" method="post"> <#if 'post'==tokenType>
<table style="width:100%"> <form id="jwt_sso_form" name="jwt_sso_form" action="${action}" method="${tokenType}">
<tr> <table style="width:100%">
<td>token</td> <tr>
<td><input type="text" id="tokenbased_token" name="${jwtName}" value="${token}" /></td> <td>token</td>
</tr> <td><input type="text" id="tokenbased_token" name="${jwtName}" value="${token}" /></td>
</tr>
<tr>
<td colspan="2"><input type="submit" name="submitBtn" value="Continue..." /></td> <tr>
</tr> <td colspan="2"><input type="submit" name="submitBtn" value="Continue..." /></td>
</table> </tr>
</form> </table>
</form>
</#if>
<#if 'get'==tokenType>
<form id="jwt_sso_form" name="jwt_sso_form" action="${action}?${jwtName}=${token}" method="${tokenType}">
<table style="width:100%">
<tr>
<td colspan="2"><input type="submit" name="submitBtn" value="Continue..." /></td>
</tr>
</table>
</form>
</#if>
</body> </body>
</html> </html>
...@@ -20,8 +20,6 @@ package org.maxkey; ...@@ -20,8 +20,6 @@ package org.maxkey;
import java.util.List; import java.util.List;
import org.maxkey.authn.AbstractAuthenticationProvider; import org.maxkey.authn.AbstractAuthenticationProvider;
import org.maxkey.authn.support.jwt.HttpJwtEntryPoint;
import org.maxkey.authn.support.jwt.JwtLoginService;
import org.maxkey.authn.web.CurrentUserMethodArgumentResolver; import org.maxkey.authn.web.CurrentUserMethodArgumentResolver;
import org.maxkey.authn.web.interceptor.PermissionInterceptor; import org.maxkey.authn.web.interceptor.PermissionInterceptor;
import org.maxkey.configuration.ApplicationConfig; import org.maxkey.configuration.ApplicationConfig;
...@@ -49,9 +47,6 @@ public class MaxKeyMgtMvcConfig implements WebMvcConfigurer { ...@@ -49,9 +47,6 @@ public class MaxKeyMgtMvcConfig implements WebMvcConfigurer {
@Autowired @Autowired
AbstractAuthenticationProvider authenticationProvider ; AbstractAuthenticationProvider authenticationProvider ;
@Autowired
JwtLoginService jwtLoginService;
@Autowired @Autowired
PermissionInterceptor permissionInterceptor; PermissionInterceptor permissionInterceptor;
...@@ -90,10 +85,7 @@ public class MaxKeyMgtMvcConfig implements WebMvcConfigurer { ...@@ -90,10 +85,7 @@ public class MaxKeyMgtMvcConfig implements WebMvcConfigurer {
//addPathPatterns 用于添加拦截规则 , 先把所有路径都加入拦截, 再一个个排除 //addPathPatterns 用于添加拦截规则 , 先把所有路径都加入拦截, 再一个个排除
//excludePathPatterns 表示改路径不用拦截 //excludePathPatterns 表示改路径不用拦截
_logger.debug("add HttpJwtEntryPoint"); _logger.debug("add HttpJwtEntryPoint");
registry.addInterceptor(new HttpJwtEntryPoint(
authenticationProvider,jwtLoginService,applicationConfig,true))
.addPathPatterns("/login");
permissionInterceptor.setMgmt(true); permissionInterceptor.setMgmt(true);
registry.addInterceptor(permissionInterceptor) registry.addInterceptor(permissionInterceptor)
......
...@@ -16,9 +16,9 @@ ...@@ -16,9 +16,9 @@
#MaxKey Server configuration # #MaxKey Server configuration #
############################################################################ ############################################################################
#server port #server port
server.port =${SERVER_PORT:9527} server.port =${SERVER_PORT:9526}
#server context path #server context path
server.servlet.context-path =/maxkey-mgt server.servlet.context-path =/maxkey-mgt-api
#nacos discovery #nacos discovery
spring.cloud.nacos.discovery.enabled =${NACOS_DISCOVERY_ENABLED:false} spring.cloud.nacos.discovery.enabled =${NACOS_DISCOVERY_ENABLED:false}
spring.cloud.nacos.discovery.instance-enabled =false spring.cloud.nacos.discovery.instance-enabled =false
...@@ -30,7 +30,7 @@ maxkey.server.scheme =http ...@@ -30,7 +30,7 @@ maxkey.server.scheme =http
maxkey.server.basedomain =${SERVER_DOMAIN:maxkey.top} maxkey.server.basedomain =${SERVER_DOMAIN:maxkey.top}
maxkey.server.domain =sso.${maxkey.server.basedomain} maxkey.server.domain =sso.${maxkey.server.basedomain}
maxkey.server.name =${maxkey.server.scheme}://${maxkey.server.domain} maxkey.server.name =${maxkey.server.scheme}://${maxkey.server.domain}
maxkey.server.uri =${maxkey.server.name}:9527${server.servlet.context-path} maxkey.server.uri =${maxkey.server.name}:${server.port}${server.servlet.context-path}
#default.uri #default.uri
maxkey.server.default.uri =${maxkey.server.uri}/main maxkey.server.default.uri =${maxkey.server.uri}/main
maxkey.server.mgt.uri =${maxkey.server.uri} maxkey.server.mgt.uri =${maxkey.server.uri}
...@@ -41,8 +41,10 @@ maxkey.server.persistence =0 ...@@ -41,8 +41,10 @@ maxkey.server.persistence =0
maxkey.server.message.queue =${SERVER_MESSAGE_QUEUE:none} maxkey.server.message.queue =${SERVER_MESSAGE_QUEUE:none}
maxkey.session.timeout =${SERVER_SESSION_TIMEOUT:1800} maxkey.session.timeout =${SERVER_SESSION_TIMEOUT:1800}
maxkey.auth.jwt.expires =86400
maxkey.auth.jwt.issuer =${maxkey.server.uri} maxkey.auth.jwt.issuer =${maxkey.server.uri}
maxkey.auth.jwt.expires =900
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
############################################################################ ############################################################################
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册