Spring MVC/Security: 从Spring Security排除登录页面

3

我正在使用Spring MVC + Security构建一个简单的Web应用程序,目前在登录方面遇到了问题。如果要保护/**(基本上是所有内容),我无法将登录页面从Spring Security中排除。以下是我的配置:

spring.security.xml

    <http pattern="/login" security="none"/>
    <http pattern="/view_register.htm" security="none"/>
    <http>
        <intercept-url pattern="/**" access="ROLE_USER" />
        <form-login login-page="/login" default-target-url="/game" authentication-failure-url="/failedlogin" />
        <logout logout-success-url="/login" />
</http>

登录控制器

@Controller
public class LoginLogoutController {

  @RequestMapping(value="/login", method = RequestMethod.GET)
  public String login(ModelMap model) {

    return "login";
  }

  @RequestMapping(value="/failedlogin", method = RequestMethod.GET)
  public String loginerror(ModelMap model) {

    model.addAttribute("error", "true");
    return "login";
  }

}

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>Login Page</title>
<style>
.errorblock {
    color: #ff0000;
    background-color: #ffEEEE;
    border: 3px solid #ff0000;
    padding: 8px;
    margin: 16px;
}
</style>
</head>
<body onload='document.f.j_username.focus();'>
    <h3>Login with Username and Password (Custom Page)</h3>

    <c:if test="${not empty error}">
        <div class="errorblock">
            Your login attempt was not successful, try again.<br /> Caused :
            ${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message}
        </div>
    </c:if>

    <form name='f' action="<c:url value='j_spring_security_check' />"
        method='POST'>

        <table>
            <tr>
                <td>User:</td>
                <td><input type='text' name='j_username' value=''>
                </td>
            </tr>
            <tr>
                <td>Password:</td>
                <td><input type='password' name='j_password' />
                </td>
            </tr>
            <tr>
                <td colspan='2'><input name="submit" type="submit"
                    value="submit" />
                </td>
            </tr>
            <tr>
                <td>Don't have an account yet.</td>
                <td> <a href="<c:url value="view_register.htm" />" > Register here</a>
                </td>
            </tr>
        </table>

    </form>
</body>
</html>

我希望保护整个应用程序,但排除登录和注册页面。在我的当前配置中,整个安全性的行为非常奇怪。如果我输入错误的凭据,

 @RequestMapping(value="/login", method = RequestMethod.GET)
  public String login(ModelMap model) {

如果我输入错误的用户名/密码,将调用登录失败控制器方法,反之正确的用户名/密码将会调用该方法。

发现如果我修改

 <intercept-url pattern="/**" access="ROLE_USER" />

to

<intercept-url pattern="/game*" access="ROLE_USER" />

并且删除

<http pattern="/login" security="none"/>

一切都按预期进行。这非常奇怪,真的无法弄清楚为什么会发生这种情况。

编辑

我刚刚创建了一个小版本的示例项目(maven),并上传到: fileswap。 任何帮助或建议都将非常酷,因为我仍然感到困惑。

2个回答

2
尝试插入以下几行代码:
<intercept-url pattern="/login/**" access="ROLE_ANONYMOUS,ROLE_USER" />
<intercept-url pattern="/failedlogin/**" access="ROLE_ANONYMOUS,ROLE_USER" />
<intercept-url pattern="/view_register/**" access="ROLE_ANONYMOUS,ROLE_USER" />

<http>标签后添加auto-config="true",保留HTML标签。
<http auto-config="true">

    <intercept-url pattern="/login/**" access="ROLE_ANONYMOUS,ROLE_USER" />
    <intercept-url pattern="/failedlogin/**" access="ROLE_ANONYMOUS,ROLE_USER" />
    <intercept-url pattern="/view_register/**" access="ROLE_ANONYMOUS,ROLE_USER" />

    <intercept-url pattern="/**" access="ROLE_USER" />

    <form-login login-page="/login" default-target-url="/game" authentication-failure-url="/failedlogin" />
    <logout logout-success-url="/login" />
</http>

并删除:

<http pattern="/login" security="none"/>

我不知道这一行是干什么的,但是它应该可以正常工作。

有关匿名身份验证的详细信息,请参见Spring Security参考文档(需要理解的重要事情是,如果匿名用户可以访问页面,并不意味着已经认证的用户也可以访问)。

BWT,ROLE_ANONYMOUS是一个内置角色,但是ROLE_USER不是,如此处所述。您需要确保将ROLE_USER分配给用户。

这个答案解释了为什么模式应该以/**结尾。


刚刚尝试了一下,效果很好!谢谢你!我会阅读你建议的文章/链接并尝试几件事情,然后再回来向你请教。非常感谢,你为我节省了很多时间。 - shippi

0

尝试使用此配置,允许匿名访问这些URL:

<http>
        <intercept-url pattern="/**" access="ROLE_USER" />
        <intercept-url pattern="/login" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
        <intercept-url pattern="/view_register.htm" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
        <form-login login-page="/login" default-target-url="/game" authentication-failure-url="/failedlogin" />
        <logout logout-success-url="/login" />
</http>

当您指定以下内容时:

<intercept-url pattern="/game*" access="ROLE_USER" />

只有像~/game*这样的URL才会受到保护,其他所有URL都不受保护。


感谢您的快速回复!我刚试了一下您的解决方案(稍作修改——只是将 /** 移动到拦截 URL 链的底部),但问题仍然存在。在访问 localhost:8080/webappName 后,我被重定向到 login.jsp,这很好。即使我没有输入任何用户名或密码,只是点击提交按钮,处理 /login 的方法也会被调用,并且我会被重定向回相同的 jsp,没有任何错误。当然,如果使用正确的凭据,则会显示错误信息:登录尝试失败,请重试。 引起的: 有趣而非常令人沮丧。 - shippi
当您指定以下内容时: <intercept-url pattern="/game*" access="ROLE_USER" /> 只有类似于~/game*的URL将受到保护,而所有其他URL将不受保护。是的,我知道,但如果我仅有/game*,login.jsp会正确地工作。如果凭据错误,则显示错误消息,如果我输入正确的密码和用户名,则可以访问/game。但是使用/**则完全相反。尝试了几个Spring安全配置的语法变体,仍然存在相同的问题。但是无论如何,感谢您的回答。 - shippi
@shippi,你能否在登录的intercept-url模式中添加*,像这样:<intercept-url pattern="/login*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>。 - sasankad
@sasankad - 仍然是一样的 :( - shippi
@shippi,那么请尝试这个<intercept-url pattern="/login*" filters="none"/>。 - sasankad
最终出现错误:不再支持使用"filters='none'"。请为要排除的模式定义一个单独的<http>元素,并使用属性"security='none'"。我正在使用spring 3.2.0版本。 - shippi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接