接前讲,首先针对一个多种用户类型的登录需求,需要先实现多种用户类型的登录界面的展示,Spring Security提供了这样一个接口来帮助我们实现多种用户类型的登录界面的展示,这个接口就是AuthenticationEntryPoint, 实现这样一个接口,我们就可以随心所欲的控制登录界面的展示了,当我们访问一个受权限的资源,而当前又没有权限访问时,Spring Security就会将处理导向这个接口的实现。针对前讲我所提到的需求,在这里我将实现前台用户和后台用户登录界面的展示,先来看看我的源码实现吧,在这里为了实现多用户类型的登录,很多场景我都需要根据相应的请求参数或地址来判断我需要导向哪个URL地址,我在这里特实现了一个共用的接口和类,接口名为DirectUrlResolver。
package com.template.security.shared; import javax.servlet.http.HttpServletRequest; /** * Created by IntelliJ IDEA. * User: Zhong Gang * Date: 12-11-9 * Time: 下午7:11 */ public interface DirectUrlResolver { boolean support(HttpServletRequest request); String directUrl(); }
package com.template.security.shared; import javax.servlet.http.HttpServletRequest; /** * Created by IntelliJ IDEA. * User: Zhong Gang * Date: 12-11-9 * Time: 下午7:12 */ public abstract class AbstractDirectUrlResolver implements DirectUrlResolver { protected String pattern; protected String directUrl; @Override public abstract boolean support(HttpServletRequest request); @Override public String directUrl() { return this.directUrl; } public void setPattern(String pattern) { this.pattern = pattern; } public void setDirectUrl(String directUrl) { this.directUrl = directUrl; } }
package com.template.security.shared; import com.template.utils.StringUtils; import javax.servlet.http.HttpServletRequest; /** * Created by IntelliJ IDEA. * User: Zhong Gang * Date: 12-11-9 * Time: 下午7:13 */ public class RequestParameterDirectUrlResolver extends AbstractDirectUrlResolver { private String parameterName; @Override public boolean support(HttpServletRequest request) { String parameterValue = request.getParameter(parameterName); if (StringUtils.isEmpty(parameterValue)) { return false; } return parameterValue.equals(this.pattern); } public void setParameterName(String parameterName) { this.parameterName = parameterName; } }
package com.template.security.shared; import javax.servlet.http.HttpServletRequest; /** * Created by IntelliJ IDEA. * User: Zhong Gang * Date: 12-11-9 * Time: 下午7:13 */ public class RequestUriDirectUrlResolver extends AbstractDirectUrlResolver { @Override public boolean support(HttpServletRequest request) { String requestURI = request.getRequestURI(); return requestURI.contains(this.pattern); } }
RequestParameterDirectUrlResolver和RequestUriDirectUrlResolver都实现了DirectUrlResolver这样一个接口,前者的实现是根据相应请求中的参数来判断, 而后者的实现是根据相应的请求地址来判断。
现在让我们来看看如何通过实现AuthenticationEntryPoint接口来控制什么时候展示前台登录界面,什么时候展示后台登录界面的吧。
package com.template.security.login; import com.template.security.shared.DirectUrlResolver; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * Created by IntelliJ IDEA. * User: Zhong Gang * Date: 12-11-9 * Time: 下午7:40 */ public class MultipleAuthenticationLoginEntry implements AuthenticationEntryPoint { private String defaultLoginUrl; private List<DirectUrlResolver> directUrlResolvers = new ArrayList<DirectUrlResolver>(); @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { for (DirectUrlResolver directUrlResolver : directUrlResolvers) { if (directUrlResolver.support(request)) { String loginUrl = directUrlResolver.directUrl(); response.sendRedirect(loginUrl); return; } } response.sendRedirect(defaultLoginUrl); } public void setDefaultLoginUrl(String defaultLoginUrl) { this.defaultLoginUrl = defaultLoginUrl; } public void setDirectUrlResolvers(List<DirectUrlResolver> directUrlResolvers) { this.directUrlResolvers = directUrlResolvers; } }
再来看看在Spring配置文件中是如何对相应的登录入口进行配置的吧
<beans:bean id="multipleAuthenticationLoginEntry" class="com.template.security.login.MultipleAuthenticationLoginEntry"> <beans:property name="defaultLoginUrl" value="/backend/login"/> <beans:property name="directUrlResolvers"> <beans:list> <beans:ref bean="backendLoginEntry"/> <beans:ref bean="forendLoginEntry"/> </beans:list> </beans:property> </beans:bean> <beans:bean id="backendLoginEntry" class="com.template.security.shared.RequestUriDirectUrlResolver"> <beans:property name="pattern" value="/backend"/> <beans:property name="directUrl" value="/backend/login"/> </beans:bean> <beans:bean id="forendLoginEntry" class="com.template.security.shared.RequestUriDirectUrlResolver"> <beans:property name="pattern" value="/forend"/> <beans:property name="directUrl" value="/forend/login"/> </beans:bean>
这里我是根据请求的地址中是否包括backend或forend来判断用户是进行前台登录或后台登录的, 这可以从配置文件中的backendLoginEntry和forendLoginEntry中的pattern属性看出,这个pattern的作用就是判断用户是进行前台登录或后台登录的依据,而directUrl则是我们想要导向的登录界面地址。