备忘代码,个人用:
这个功能经常用,每次都从头写太麻烦,记下来备用。
spring-security配置:
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<debug />
<http entry-point-ref="casEntryPoint">
<custom-filter ref="casFilter" position="CAS_FILTER" />
<logout logout-success-url="/logout/cas" />
<custom-filter ref="requestSingleLogoutFilter" before="LOGOUT_FILTER" />
<custom-filter ref="singleLogoutFilter" before="CAS_FILTER" />
<cors />
<csrf disabled="true" />
<!-- 登录用URL -->
<intercept-url pattern="/getlogin" access="isAuthenticated()" />
<!-- 管理员接口URL -->
<intercept-url pattern="/api/adm/**"
access="hasAnyAuthority('ROLE_ADMINISTRATOR','ROLE_BUSINESS','ROLE_TECHNICAL')" />
<!-- 需权接口 -->
<intercept-url pattern="/api/auth/**" access="isAuthenticated()" />
<!-- 管理员页面URL -->
<intercept-url pattern="/adm/**" access="hasAnyAuthority('ROLE_ADMINISTRATOR','ROLE_BUSINESS','ROLE_TECHNICAL')" />
<!-- 其余URL无需权限 -->
<intercept-url pattern="/**" access="permitAll" />
<headers>
<frame-options disabled="true" />
</headers>
</http>
<context:property-placeholder location="classpath:spring-config.properties" />
<beans:bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
<beans:property name="service" value="${spring.security.serviceProperties.service}" />
<beans:property name="sendRenew" value="false" />
</beans:bean>
<beans:bean id="casEntryPoint" class="com.s.ad.springcomponent.CustomedCasAuthenticationEntryPoint">
<beans:property name="loginUrl" value="${spring.security.casEntryPoint.loginUrl}" />
<beans:property name="serviceProperties" ref="serviceProperties" />
<beans:property name="noNeedToFilterUrlPrefix">
<beans:list>
<beans:value>/getlogin</beans:value>
<beans:value>/api/adm</beans:value>
</beans:list>
</beans:property>
</beans:bean>
<beans:bean id="casFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="authenticationSuccessHandler">
<beans:bean class="com.s.ad.springcomponent.CustomedSavedRequestAwareAuthenticationSuccessHandler">
<beans:property name="alwaysUseDefaultTargetUrl" value="false" />
<beans:property name="targetUrlParameter" value="redirectUrl" />
</beans:bean>
</beans:property>
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="casAuthenticationProvider" />
</authentication-manager>
<beans:bean id="casAuthenticationProvider"
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<beans:property name="authenticationUserDetailsService">
<beans:bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<beans:constructor-arg ref="userService" />
</beans:bean>
</beans:property>
<beans:property name="serviceProperties" ref="serviceProperties" />
<beans:property name="ticketValidator">
<beans:bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<beans:constructor-arg index="0"
value="${spring.security.casAuthenticationProvider.ticketValidator.arg0}" />
</beans:bean>
</beans:property>
<beans:property name="key" value="an_id_for_this_auth_provider_only" />
</beans:bean>
<ldap-user-service id="userService" user-search-filter="(uid={0})" user-search-base="ou=People"
group-search-filter="(memberUid={1})" group-search-base="ou=Group" />
<ldap-server url="${spring.security.ldap-server.url}" manager-dn="cn=Manager,dc=s,dc=com"
manager-password="43b2f162-ea30-42c6-9a87-d67ea630d118" />
<beans:bean id="singleLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter">
<beans:property name="casServerUrlPrefix" value="${spring.security.singleLogoutFilter.casServerUrlPrefix}" />
</beans:bean>
<beans:bean id="requestSingleLogoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<beans:constructor-arg value="${spring.security.requestSingleLogoutFilter.arg0}" />
<beans:constructor-arg>
<beans:bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" />
</beans:constructor-arg>
<beans:property name="filterProcessesUrl" value="/logout/cas" />
</beans:bean>
</beans:beans>
将CasAuthenticationEntryPoint的代码copy过来修改一下,spring自带的CasAuthenticationEntryPoint有点限制,不好用,修改后代码如下:
package com.s.ad.springcomponent;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jasig.cas.client.Protocol;
import org.jasig.cas.client.util.CommonUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.http.HttpStatus;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.util.Assert;
public class CustomedCasAuthenticationEntryPoint implements AuthenticationEntryPoint, InitializingBean {
// ~ Instance fields
// ================================================================================================
private ServiceProperties serviceProperties;
private String loginUrl;
/**
* 以这些前缀开头的URL会走正常登录逻辑,而不是向客户端返回403提示
*/
private String[] noNeedToFilterUrlPrefix;
/**
* Determines whether the Service URL should include the session id for the specific
* user. As of CAS 3.0.5, the session id will automatically be stripped. However,
* older versions of CAS (i.e. CAS 2), do not automatically strip the session
* identifier (this is a bug on the part of the older server implementations), so an
* option to disable the session encoding is provided for backwards compatibility.
*
* By default, encoding is enabled.
*/
private boolean encodeServiceUrlWithSessionId = true;
// ~ Methods
// ========================================================================================================
public void afterPropertiesSet() throws Exception {
Assert.hasLength(this.loginUrl, "loginUrl must be specified");
Assert.notNull(this.serviceProperties, "serviceProperties must be specified");
Assert.notNull(this.serviceProperties.getService(), "serviceProperties.getService() cannot be null.");
}
public final void commence(final HttpServletRequest servletRequest, final HttpServletResponse response, final AuthenticationException authenticationException)
throws IOException, ServletException {
final String urlEncodedService = createServiceUrl(servletRequest, response);
final String redirectUrl = createRedirectUrl(urlEncodedService);
preCommence(servletRequest, response);
/**
* 判断当前URL是否匹配无需过滤的前缀,若匹配,则走正常登录逻辑,否则向客户端返回提示信息
*/
boolean c = true;
if (noNeedToFilterUrlPrefix != null) {
f: for (String urlPrefix : noNeedToFilterUrlPrefix) {
if (servletRequest.getServletPath().startsWith(urlPrefix)) {
response.sendRedirect(redirectUrl);
c = false;
break f;
}
}
}
if (c) {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpStatus.OK.value());
String s = "{\"code\":403,\"msg\":\"forbidden\",\"err_msg\":\"Login expired\"}";
PrintWriter writer = response.getWriter();
writer.write(s);
writer.close();
response.flushBuffer();
}
}
/**
* Constructs a new Service Url. The default implementation relies on the CAS client
* to do the bulk of the work.
* @param request the HttpServletRequest
* @param response the HttpServlet Response
* @return the constructed service url. CANNOT be NULL.
*/
protected String createServiceUrl(final HttpServletRequest request, final HttpServletResponse response) {
Set<String> serviceParameterSet = new HashSet<String>(4);
for (final Protocol protocol : Protocol.values()) {
serviceParameterSet.add(protocol.getServiceParameterName());
}
String serviceParameterName = serviceParameterSet.toString().replaceAll("\\[|\\]", "").replaceAll("\\s", "");
return CommonUtils.constructServiceUrl(null, response, this.serviceProperties.getService(), null, serviceParameterName, this.serviceProperties.getArtifactParameter(),
this.encodeServiceUrlWithSessionId);
}
/**
* Constructs the Url for Redirection to the CAS server. Default implementation relies
* on the CAS client to do the bulk of the work.
*
* @param serviceUrl the service url that should be included.
* @return the redirect url. CANNOT be NULL.
*/
protected String createRedirectUrl(final String serviceUrl) {
return CommonUtils.constructRedirectUrl(this.loginUrl, this.serviceProperties.getServiceParameter(), serviceUrl, this.serviceProperties.isSendRenew(), false);
}
/**
* Template method for you to do your own pre-processing before the redirect occurs.
*
* @param request the HttpServletRequest
* @param response the HttpServletResponse
*/
protected void preCommence(final HttpServletRequest request, final HttpServletResponse response) {
}
/**
* The enterprise-wide CAS login URL. Usually something like
* <code>https://www.mycompany.com/cas/login</code>.
*
* @return the enterprise-wide CAS login URL
*/
public final String getLoginUrl() {
return this.loginUrl;
}
public String[] getNoNeedToFilterUrlPrefix() {
return noNeedToFilterUrlPrefix;
}
public final ServiceProperties getServiceProperties() {
return this.serviceProperties;
}
public final void setLoginUrl(final String loginUrl) {
this.loginUrl = loginUrl;
}
public void setNoNeedToFilterUrlPrefix(String[] noNeedToFilterUrlPrefix) {
this.noNeedToFilterUrlPrefix = noNeedToFilterUrlPrefix;
}
public final void setServiceProperties(final ServiceProperties serviceProperties) {
this.serviceProperties = serviceProperties;
}
/**
* Sets whether to encode the service url with the session id or not.
*
* @param encodeServiceUrlWithSessionId whether to encode the service url with the
* session id or not.
*/
public final void setEncodeServiceUrlWithSessionId(final boolean encodeServiceUrlWithSessionId) {
this.encodeServiceUrlWithSessionId = encodeServiceUrlWithSessionId;
}
/**
* Sets whether to encode the service url with the session id or not.
* @return whether to encode the service url with the session id or not.
*
*/
protected boolean getEncodeServiceUrlWithSessionId() {
return this.encodeServiceUrlWithSessionId;
}
}
SavedRequestAwareAuthenticationSuccessHandler也要copy然后自定义下,如下:
if (isAlwaysUseDefaultTargetUrl()
|| (targetUrlParameter != null && StringUtils.hasText(request.getParameter(targetUrlParameter)))) {
requestCache.removeRequest(request, response);
super.onAuthenticationSuccess(request, response, authentication);
return;
}
clearAuthenticationAttributes(request);
{ // 根据是否有targetUrlParameter代表的参数进行响应的处理,将用户重定向到不同targetUrl
String targetUrl = null;
String[] targetUrls = savedRequest.getParameterMap().get(targetUrlParameter);
if (targetUrls != null && targetUrls.length > 0) { // 可从savedRequest取到targetUrl
targetUrl = targetUrls[0];
} else { // 不能从savedRequest取到targetUrl,则使用默认值
targetUrl = savedRequest.getRedirectUrl();
}
getRedirectStrategy().sendRedirect(request, response, targetUrl);
}