From c9810dd062d5811c26ae1da6073a7a4bea9e795d Mon Sep 17 00:00:00 2001 From: shimingxy Date: Fri, 16 Jan 2026 15:17:43 +0800 Subject: [PATCH] =?UTF-8?q?#IDGR9O=20cas=E7=99=BB=E5=BD=95grantingTicket?= =?UTF-8?q?=E7=94=9F=E6=88=90=E7=9A=84url=E4=BC=9A=E6=9C=89=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/dromara/maxkey/http/HttpUtils.java | 82 ++++++++++++++++ .../cas/endpoint/CasAuthorizeEndpoint.java | 95 ++++++++----------- 2 files changed, 122 insertions(+), 55 deletions(-) create mode 100644 maxkey-commons/maxkey-common/src/main/java/org/dromara/maxkey/http/HttpUtils.java diff --git a/maxkey-commons/maxkey-common/src/main/java/org/dromara/maxkey/http/HttpUtils.java b/maxkey-commons/maxkey-common/src/main/java/org/dromara/maxkey/http/HttpUtils.java new file mode 100644 index 000000000..377d9b156 --- /dev/null +++ b/maxkey-commons/maxkey-common/src/main/java/org/dromara/maxkey/http/HttpUtils.java @@ -0,0 +1,82 @@ +/* + * Copyright [2025] [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. + */ + + + +package org.dromara.maxkey.http; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.lang3.ObjectUtils; + +public class HttpUtils { + + /** + * https://cas.maxkey.top/casserver/authz?aaa=aaa&bbb=bbb
+ * return
+ * https://cas.maxkey.top/casserver/authz + * @param param + * @return + */ + public static String requestUrl(String param){ + String url = param; + if(param.indexOf("?") > -1) { + url = param.substring(0, param.indexOf("?")); + } + return url; + } + + /** + * 把map参数加到url后 + * @param url + * @param parameterMap + * @return + */ + public static String appendToUrl(String url,Map parameterMap){ + StringBuffer appendedUrl = new StringBuffer(url); + if(ObjectUtils.isNotEmpty(parameterMap)) { + for (Entry entry : parameterMap.entrySet()) { + appendedUrl.append((appendedUrl.indexOf("?") == -1)?"?":"&") + .append(entry.getKey()).append("=").append(entry.getValue()); + } + } + return appendedUrl.toString(); + } + + /** + * https://cas.maxkey.top/casserver/authz?aaa=aaa&bbb=bbb
+ * 把aaa=aaa&bbb=bbb转换成map + * @param param + * @return Map + */ + public static Map queryStringToMap(String param){ + String urlParam = param; + Map paramMap = new HashMap(); + if(param.indexOf("?") > -1) { + urlParam = param.substring(param.indexOf("?") + 1); + } + String[] params = urlParam.split("&"); + for(String keyValue : params){ + String[] paramValue = keyValue.split("="); + if(paramValue.length == 2){ + paramMap.put(paramValue[0], paramValue[1]); + } + } + return paramMap; + } +} diff --git a/maxkey-protocols/maxkey-protocol-cas/src/main/java/org/dromara/maxkey/authz/cas/endpoint/CasAuthorizeEndpoint.java b/maxkey-protocols/maxkey-protocol-cas/src/main/java/org/dromara/maxkey/authz/cas/endpoint/CasAuthorizeEndpoint.java index aed39e8ba..dc4de1e46 100644 --- a/maxkey-protocols/maxkey-protocol-cas/src/main/java/org/dromara/maxkey/authz/cas/endpoint/CasAuthorizeEndpoint.java +++ b/maxkey-protocols/maxkey-protocol-cas/src/main/java/org/dromara/maxkey/authz/cas/endpoint/CasAuthorizeEndpoint.java @@ -14,22 +14,20 @@ * limitations under the License. */ - -/** - * - */ package org.dromara.maxkey.authz.cas.endpoint; import java.security.Principal; +import java.util.HashMap; import java.util.Map; -import java.util.Map.Entry; +import org.apache.commons.lang3.ObjectUtils; import org.dromara.maxkey.authn.session.VisitedDto; import org.dromara.maxkey.authn.web.AuthorizationUtils; import org.dromara.maxkey.authz.cas.ticket.CasConstants; import org.dromara.maxkey.authz.cas.ticket.ServiceTicketImpl; import org.dromara.maxkey.authz.singlelogout.LogoutType; import org.dromara.maxkey.entity.apps.AppsCasDetails; +import org.dromara.maxkey.http.HttpUtils; import org.dromara.maxkey.web.WebConstants; import org.dromara.maxkey.web.WebContext; import org.slf4j.Logger; @@ -61,9 +59,9 @@ public class CasAuthorizeEndpoint extends CasBaseAuthorizeEndpoint{ HttpServletRequest request, HttpServletResponse response ){ - - AppsCasDetails casDetails = casDetailsService.getAppDetails(casService , true); - + String queryService = HttpUtils.requestUrl(casService); + _logger.debug("service {}" , queryService); + AppsCasDetails casDetails = casDetailsService.getAppDetails(queryService , true); return buildCasModelAndView(request,response,casDetails,casService); } @@ -90,20 +88,21 @@ public class CasAuthorizeEndpoint extends CasBaseAuthorizeEndpoint{ return modelAndView; } - _logger.debug("Detail {}" , casDetails); - Map parameterMap = WebContext.getRequestParameterMap(request); - String service = casService; - _logger.debug("CAS Parameter service = {}" , service); - if(casService.indexOf("?") >-1 ) { - service = casService.substring(casService.indexOf("?") + 1); - if(service.indexOf("=") > -1) { - String [] parameterValues = service.split("="); - if(parameterValues.length == 2) { - parameterMap.put(parameterValues[0], parameterValues[1]); - } - } - _logger.debug("CAS service with Parameter : {}" , parameterMap); + _logger.debug("CAS service = {} , Detail {}" , casService,casDetails); + Map parameterMap = new HashMap<>(); + //配置参数 + Map serviceParamMap = HttpUtils.queryStringToMap(casDetails.getCallbackUrl()); + if(ObjectUtils.isNotEmpty(serviceParamMap)) { + parameterMap.putAll(serviceParamMap); } + _logger.debug("CAS CallbackUrl Parameter : {}" , parameterMap); + //请求参数 + Map requestParameterMap = WebContext.getRequestParameterMap(request); + if(ObjectUtils.isNotEmpty(requestParameterMap)) { + parameterMap.putAll(requestParameterMap); + } + parameterMap.put(CasConstants.PARAMETER.SERVICE, casService); + _logger.debug("CAS service with Parameter : {}" , parameterMap); WebContext.setAttribute(CasConstants.PARAMETER.PARAMETER_MAP, parameterMap); WebContext.setAttribute(CasConstants.PARAMETER.ENDPOINT_CAS_DETAILS, casDetails); WebContext.setAttribute(WebConstants.SINGLE_SIGN_ON_APP_ID, casDetails.getId()); @@ -118,49 +117,35 @@ public class CasAuthorizeEndpoint extends CasBaseAuthorizeEndpoint{ HttpServletResponse response){ ModelAndView modelAndView = new ModelAndView("authorize/cas_sso_submint"); AppsCasDetails casDetails = (AppsCasDetails)WebContext.getAttribute(CasConstants.PARAMETER.ENDPOINT_CAS_DETAILS); - ServiceTicketImpl serviceTicket = new ServiceTicketImpl(AuthorizationUtils.getAuthentication(),casDetails); + @SuppressWarnings("unchecked") + Map parameterMap = (Map )WebContext.getAttribute(CasConstants.PARAMETER.PARAMETER_MAP); + if(parameterMap == null) { + parameterMap = new HashMap<>(); + } - _logger.trace("CAS start create ticket ... "); String ticket = ticketServices.createTicket(serviceTicket,casDetails.getExpires()); - _logger.trace("CAS ticket {} created . " , ticket); - - StringBuffer callbackUrl = new StringBuffer(casDetails.getCallbackUrl()); - if(casDetails.getCallbackUrl().indexOf("?")==-1) { - callbackUrl.append("?"); - } - - if(callbackUrl.indexOf("&") != -1 ||callbackUrl.indexOf("=") != -1) { - callbackUrl.append("&"); - } - - //append ticket - callbackUrl.append(CasConstants.PARAMETER.TICKET).append("=").append(ticket); - - callbackUrl.append("&"); - //append service - callbackUrl.append(CasConstants.PARAMETER.SERVICE).append("=").append(casDetails.getService()); - - //增加可自定义的参数 - if(WebContext.getAttribute(CasConstants.PARAMETER.PARAMETER_MAP)!=null) { - @SuppressWarnings("unchecked") - Map parameterMap = (Map )WebContext.getAttribute(CasConstants.PARAMETER.PARAMETER_MAP); - parameterMap.remove(CasConstants.PARAMETER.TICKET); - parameterMap.remove(CasConstants.PARAMETER.SERVICE); - for (Entry entry : parameterMap.entrySet()) { - callbackUrl.append("&").append(entry.getKey()).append("=").append(entry.getValue()); - } - } - + _logger.trace("CAS ticket {} created for App {} Name {} " , ticket , casDetails.getId(),casDetails.getAppName()); + if(casDetails.getLogoutType()==LogoutType.BACK_CHANNEL) { - _logger.debug("CAS LogoutType BACK_CHANNEL ... "); String sessionId = AuthorizationUtils.getPrincipal().getSessionId(); VisitedDto visited = new VisitedDto(casDetails,ticket); sessionManager.visited(sessionId, visited); - _logger.debug("App id {} , name {} , CAS LogoutType BACK_CHANNEL ... " , casDetails.getId(),casDetails.getAppName()); + _logger.debug("App CAS LogoutType BACK_CHANNEL ... "); } - _logger.debug("redirect to CAS Client URL {}" , callbackUrl); + //去除?和后面的参数 + String callbackUri = HttpUtils.requestUrl(casDetails.getCallbackUrl()); + //ticket + parameterMap.put(CasConstants.PARAMETER.TICKET, ticket); + //service + if(!parameterMap.containsKey(CasConstants.PARAMETER.SERVICE)) { + parameterMap.put(CasConstants.PARAMETER.SERVICE, casDetails.getService()); + } + //增加可自定义的参数 + String callbackUrl = HttpUtils.appendToUrl(callbackUri, parameterMap); + + _logger.debug("redirect to CAS URL {}" , callbackUrl); modelAndView.addObject("callbackUrl", callbackUrl.toString()); return modelAndView; }