第 50 章 多个登陆页面

实际就是想让不同的用户看到的是不同的登录页面,比如前台用户进入的页面要多放广告和新闻,而后台管理登陆页面就可以朴素点儿。

50.1. 未登录自动跳转到对应的登录页面

因为Spring Security会使用AuthenticationEntryPoint在未登录用户访问被保护资源时自动跳转到登录页面,所以我们这里需要的就是扩展AuthenticaitonEntryPoint。

public class LoginPageEntryPoint implements AuthenticationEntryPoint,
    InitializingBean {
    private LoginPageStrategy loginPageStrategy;

    public void afterPropertiesSet() throws Exception {
        Assert.notNull(loginPageStrategy,
            "loginPageStrategy must be specified");
    }

    public void commence(HttpServletRequest request,
        HttpServletResponse response, AuthenticationException authException)
        throws IOException, ServletException {
        loginPageStrategy.process((HttpServletRequest) request,
            (HttpServletResponse) response);
    }

    public void setLoginPageStrategy(LoginPageStrategy loginPageStrategy) {
        this.loginPageStrategy = loginPageStrategy;
    }
}
        

这里的LoginPageEntryPoint所作的工作就是将request和response转换为HttpServletRequest和HttpServletResponse,然后交给LoginPageStrategy进行处理,实际的操作都写在LoginPageStrategy中。

这里我们提供了两个简单的实现类,用来演示根据ip或者url来为用户显示不同的登录页面的功能。

首先是IpMappingLoginPageStrategy,它的作用是当请求来自127.0.0.1时,就会显示管理员的登陆页面,否则显示普通用户的登录页面。

public class IpMappingLoginPageStrategy implements LoginPageStrategy {
    public void process(HttpServletRequest request,
        HttpServletResponse response) throws IOException, ServletException {
        String targetUrl = null;
        String ip = request.getRemoteAddr();

        if ("127.0.0.1".equals(ip)) {
            targetUrl = "/login/admin.jsp";
        } else {
            targetUrl = "/login/user.jsp";
        }

        targetUrl = request.getContextPath() + targetUrl;
        response.sendRedirect(targetUrl);
    }
}
        

然后是UrlMappingLoginPageStrategy,它会判断用户当前请求的URL,如果URL中包含了“/admin”就跳转到管理员登陆页面,否则跳转到用户登录页面。

public class UrlMappingLoginPageStrategy implements LoginPageStrategy {
    public void process(HttpServletRequest request,
        HttpServletResponse response) throws IOException, ServletException {
        String targetUrl = null;
        String uri = request.getRequestURI();

        if (uri.indexOf("admin") != -1) {
            targetUrl = "/login/admin.jsp";
        } else {
            targetUrl = "/login/user.jsp";
        }

        targetUrl = request.getContextPath() + targetUrl;
        response.sendRedirect(targetUrl);
    }
}
        

实际配置时,我们演示使用UrlMappingLoginPageStrategy的情况。

<http auto-config='true' entry-point-ref="loginPageEntryPoint">
    <intercept-url pattern="/login/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    <intercept-url pattern="/admin.jsp" access="ROLE_ADMIN" />
    <intercept-url pattern="/**" access="ROLE_USER" />
</http>

<beans:bean id="loginPageEntryPoint" class="com.family168.springsecuritybook.ch218.LoginPageEntryPoint">
    <beans:property name="loginPageStrategy" ref="urlMappingLoginPageStrategy"/>
</beans:bean>

<beans:bean id="urlMappingLoginPageStrategy"
    class="com.family168.springsecuritybook.ch218.UrlMappingLoginPageStrategy"/>
        

访问http://localhost:8080/user就会显示用户登录页面。

用户登录页面

图 50.1. 用户登录页面


访问http://localhost:8080/admin就会显示管理员登陆页面。

管理员登录页面

图 50.2. 管理员登录页面


50.2. 密码出错时返回对应页面

本来应该扩展AuthenticationProcessFilter,但是因为现在比较懒,所以直接写了一个password-wrong.jsp来替代,里边根据登录的类型决定跳转到哪个页面,实现在对应页面中显示错误信息。

<%
    String loginType = (String) session.getAttribute("loginType");
    if ("admin".equals(loginType)) {
        response.sendRedirect("admin.jsp?error=true");
    } else {
        response.sendRedirect("user.jsp?error=true");
    }
%>
        

在配置文件中添加password-wrong.jsp的配置。

<form-login authentication-failure-url="/login/password-wrong.jsp"/>
        

实例见ch218。