Contexto: recebi hoje um pedido de que o cas pode ser redirecionado para qualquer site da Web. Recomenda-se realizar uma correspondência regular estrita no URL redirecionado ou não usar os parâmetros passados do front end como base para o redirecionamento.
Artigo Diretório
1. Pessoas preguiçosas olham primeiro
O redirecionamento do logout do cas ainda é muito bom em termos de design.Já ajudou você a considerar o controle de segurança do escopo do redirecionamento do logout.O problema mencionado no fundo é totalmente causado por nossa configuração inadequada.
Então, como o CAS habilita o controle de segurança de redirecionamento?
Muito simples, basta cas.logout.followServiceRedirects
definir como verdadeiro; o padrão do sistema é falso.
##
# CAS Logout Behavior
# WEB-INF/cas-servlet.xml
#
# Specify whether CAS should redirect to the specified service parameter on /logout requests
cas.logout.followServiceRedirects=true
Então, como o CAS realiza o controle de segurança de redirecionamento?
A seguir, vamos dar uma olhada no controle de processo do CAS com o Sr. Zihan ~
Em segundo lugar, controle de processo de logout cas
Sabemos que os processos de login e logout do cas são definidos por login-webflow.xml e logout-webflow.xml respectivamente.
1. Entenda o Spring Webflow
A pilha de tecnologia usada pela definição do processo de logout do cas é Spring webflow, o endereço do site oficial . Por exemplo, decision-state
seleção de processos e action-state
componentes de execução:
- Selecione os componentes
<decision-state id="serviceCheck">
<if test="flowScope.service != null" then="generateServiceTicket" else="viewGenericLoginSuccess" />
</decision-state>
- Componente executivo
<action-state id="redirect">
<evaluate expression="flowScope.service.getResponse(requestScope.serviceTicketId)" result-type="org.jasig.cas.authentication.principal.Response" result="requestScope.response" />
<transition to="postRedirectDecision" />
</action-state>
Leitura estendida: https://www.cnblogs.com/shuyuq/p/9729791.html
2. Saia e redirecione o posicionamento da chave
A propósito, o Sr. Zihan gostaria de compartilhar com você alguma experiência na leitura de código-fonte ~
Em circunstâncias normais, às vezes não conseguimos encontrar o local de entrada do código-fonte de empresas relacionadas de uma vez. Podemos
1. Podemos localizar o código-chave primeiro e depois usar a ordem inversa para ler.
2. Em seguida, leia o princípio do código-fonte e entenda profundamente seu processo de execução por meio da configuração de sequência positiva.
Ao analisar o código-fonte aqui, nós o lemos na ordem inversa.
- Encontre o código-fonte redirecionado para a localização do url externo
<!--
The "redirect" end state allows CAS to properly end the workflow while still redirecting
the user back to the service required.
-->
<end-state id="redirectView" view="externalRedirect:#{requestScope.response.url}" />
- Encontre a etapa anterior
<!--检查cas管理的service范围,成功时支持重定向-->
<action-state id="gatewayServicesManagementCheck">
<evaluate expression="gatewayServicesManagementCheck" />
<transition on="success" to="redirect" />
</action-state>
<!--重定向事件执行,post请求时返回post结果 -->
<action-state id="redirect">
<evaluate expression="flowScope.service.getResponse(requestScope.serviceTicketId)" result-type="org.jasig.cas.authentication.principal.Response" result="requestScope.response" />
<transition to="postRedirectDecision" />
</action-state>
<decision-state id="postRedirectDecision">
<if test="requestScope.response.responseType.name() == 'POST'" then="postView" else="redirectView" />
</decision-state>
gatewayServicesManagementCheck
É um bean responsável pela detecção de serviço e gerenciado pelo Spring.
<bean id="gatewayServicesManagementCheck" class="org.jasig.cas.web.flow.GatewayServicesManagementCheck"
c:servicesManager-ref="servicesManager"/>
Veja o código-fonte:
org.jasig.cas.web.flow.GatewayServicesManagementCheck
public class GatewayServicesManagementCheck extends AbstractAction {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@NotNull
private final ServicesManager servicesManager;
/**
* Initialize the component with an instance of the services manager.
* @param servicesManager the service registry instance.
*/
public GatewayServicesManagementCheck(final ServicesManager servicesManager) {
this.servicesManager = servicesManager;
}
@Override
protected Event doExecute(final RequestContext context) throws Exception {
final Service service = WebUtils.getService(context);
final boolean match = this.servicesManager.matchesExistingService(service);
if (match) {
return success();
}
final String msg = String.format("ServiceManagement: Unauthorized Service Access. "
+ "Service [%s] does not match entries in service registry.", service.getId());
logger.warn(msg);
throw new UnauthorizedServiceException(UnauthorizedServiceException.CODE_UNAUTHZ_SERVICE, msg);
}
}
3. Olhe para o processo de saída do CAS novamente
3-1 Entrada de processo
O logout-webflow.xml define o método de saída baseado em url:
<!-- 通过后端触发的退出 -->
<action-state id="doLogout">
<evaluate expression="logoutAction" />
<transition on="finish" to="finishLogout" />
<transition on="front" to="frontLogout" />
</action-state>
3-2 Sair da execução
Cas dá a ação de saída para o logoutAction
Bean, e os followServiceRedirects
parâmetros no Bean definem o intervalo de endereço URL de logout de redirecionamento:
<!-- 退出功能控制器,前端带你退出走这个action -->
<bean id="logoutAction" class="org.jasig.cas.web.flow.LogoutAction"
p:servicesManager-ref="servicesManager"
p:followServiceRedirects="${cas.logout.followServiceRedirects:false}"/>
O logoutAction
código-fonte:
/**
* Action to delete the TGT and the appropriate cookies.
* It also performs the back-channel SLO on the services accessed by the user during its browsing.
* After this back-channel SLO, a front-channel SLO can be started if some services require it.
* The final logout page or a redirection url is also computed in this action.
*
* @author Scott Battaglia
* @author Jerome Leleu
* @since 3.0
*/
public final class LogoutAction extends AbstractLogoutAction {
/** The services manager. */
@NotNull
private ServicesManager servicesManager;
/**
* Boolean to determine if we will redirect to any url provided in the
* service request parameter.
*/
private boolean followServiceRedirects;
@Override
protected Event doInternalExecute(final HttpServletRequest request, final HttpServletResponse response,
final RequestContext context) throws Exception {
boolean needFrontSlo = false;
putLogoutIndex(context, 0);
final List<LogoutRequest> logoutRequests = WebUtils.getLogoutRequests(context);
if (logoutRequests != null) {
for (LogoutRequest logoutRequest : logoutRequests) {
// if some logout request must still be attempted
if (logoutRequest.getStatus() == LogoutRequestStatus.NOT_ATTEMPTED) {
needFrontSlo = true;
break;
}
}
}
//==========小哥哥、小姐姐们,看这里~ start===============
final String service = request.getParameter("service");
if (this.followServiceRedirects && service != null) {
final RegisteredService rService = this.servicesManager.findServiceBy(new SimpleWebApplicationServiceImpl(service));
if (rService != null && rService.isEnabled()) {
context.getFlowScope().put("logoutRedirectUrl", service);
}
}
//==========小哥哥、小姐姐们,看这里~ end===============
// there are some front services to logout, perform front SLO
//匹配到cas管理的service范围,退出后跳转到对应的service地址。
if (needFrontSlo) {
return new Event(this, FRONT_EVENT);
} else {
// otherwise, finish the logout process
//否则,退出到cas默认的退出地址
return new Event(this, FINISH_EVENT);
}
}
public void setFollowServiceRedirects(final boolean followServiceRedirects) {
this.followServiceRedirects = followServiceRedirects;
}
public void setServicesManager(final ServicesManager servicesManager) {
this.servicesManager = servicesManager;
}
}
3-3 Redirecionamento de serviço
- Encontre o serviço correspondente e devolva :,
context.getFlowScope().put("logoutRedirectUrl", service);
dê-o afinishLogout
<decision-state id="finishLogout">
<if test="flowScope.logoutRedirectUrl != null" then="redirectView" else="logoutView" />
</decision-state>
- Caso contrário, saia para o endereço de logout padrão
Obrigado pela sua apreciação, oficial convidado, por favor clique em curtir e saia ~