【问题标题】:Password protecting two web pages with Spring 3.1使用 Spring 3.1 保护两个网页的密码
【发布时间】:2014-02-14 17:15:16
【问题描述】:

我一直在寻找与我很接近的问题,但似乎找不到我正在寻找的确切答案。我猜我想要做的解决方案相当简单。

我有一个带有默认页面 (index.jsp) 的网站。有一个从索引页面到管理页面 (admin.jsp) 的链接。此页面已使用 Spring 进行了很长时间的密码保护,没有问题。这是我一直在使用的安全上下文文件:

<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"
             xsi:schemaLocation="http://www.springframework.org/schema/beans 
                    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                    http://www.springframework.org/schema/security 
                    http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <global-method-security pre-post-annotations="enabled" secured-annotations="enabled"/>     

    <http use-expressions="true">
        <intercept-url pattern="/admin.jsp" access="hasRole('administrator')" />
        <intercept-url pattern="/**" access="permitAll" />
        <form-login login-page="/login.jsp" default-target-url="/admin.jsp" />
        <logout />
    </http>

    <authentication-manager>
        <authentication-provider>
            <user-service>
                <user name="${admin.username}" password="${admin.password}" authorities="administrator" />
            </user-service>
        </authentication-provider>
    </authentication-manager>
</beans:beans>   

我现在也需要密码保护 index.jsp。如果我复制元素的子元素(并且我创建了单独的 login.jsp 文件,不确定是否有必要),如下所示:

<http use-expressions="true">
        <intercept-url pattern="/index.jsp" access="hasRole('user')" />
        <form-login login-page="/indexLogin.jsp" default-target-url="/index.jsp" />
        <logout />

        <intercept-url pattern="/admin.jsp" access="hasRole('administrator')" />
        <form-login login-page="/adminLogin.jsp" default-target-url="/admin.jsp" />
        <logout />
    </http>

    <authentication-manager>
        <authentication-provider>
            <user-service>
                <user name="${admin.username}" password="${admin.password}" authorities="administrator" />
                <user name="${user.username}" password="${user.password}" authorities="user" />
            </user-service>
        </authentication-provider>
    </authentication-manager>

那么 index.jsp 就像预期的那样受到密码保护。但是,如果我单击在新选项卡中打开 admin.jsp 页面的按钮,我会收到 403 - Access is denied 错误。我假设这是因为它会自动尝试使用管理页面上的用户凭据。

然后我尝试创建两个单独的元素,每个元素都有每个不同页面的元素:

<http use-expressions="true">
        <intercept-url pattern="/index.jsp" access="hasRole('user')" />
        <form-login login-page="/indexLogin.jsp" default-target-url="/index.jsp" />
        <logout />
    </http>

    <http use-expressions="true">
        <intercept-url pattern="/admin.jsp" access="hasRole('administrator')" />
        <form-login login-page="/adminLogin.jsp" default-target-url="/admin.jsp" />
        <logout />
    </http>

然后我收到一条错误消息:

java.lang.IllegalArgumentException:通用匹配模式('/**')在过滤器链中的其他模式之前定义,导致它们被忽略。请检查您的命名空间或 FilterChainProxy bean 配置中的排序

谁能告诉我如何强制 Spring 在每次访问 index.jsp 或 admin.jsp 时提示输入凭据,而不是假定应该使用现有凭据?

【问题讨论】:

    标签: java spring jsp spring-mvc spring-security


    【解决方案1】:

    您可能不需要 Spring Security “在每次访问 index.jspadmin.jsp 时提示输入凭据”。 这不是 Spring Security 的常见用例,即使你设法做到了,它也会使事情变得更加复杂。

    相反,您可以在用户访问您的应用程序的任何网页时对用户进行身份验证(即您只提示输入登录名和密码一次)。当用户尝试访问admin.jsp时,您可以 使用您已经拥有的用户凭据来允许或拒绝访问此页面。

    您需要将原始代码中的access="permitAll" 替换为access="hasRole('user')"。所以你的&lt;http&gt; 标签应如下所示:

    <http use-expressions="true">
        <intercept-url pattern="/admin.jsp" access="hasRole('administrator')" />
        <intercept-url pattern="/**" access="hasRole('user')" />
        <form-login login-page="/login.jsp" default-target-url="/admin.jsp" />
        <logout />
    </http>
    

    另外,在&lt;authentication-manager&gt; 标记中保留您自己的更改,但将authorities="administrator" 替换为authorities="user,administrator"

    <authentication-manager>
        <authentication-provider>
            <user-service>
                <user name="${admin.username}" password="${admin.password}" authorities="user,administrator" />
                <user name="${user.username}" password="${user.password}" authorities="user" />
            </user-service>
        </authentication-provider>
    </authentication-manager>
    

    Spring Security 按照定义的顺序匹配&lt;intercept-url&gt; 规则。首先,它将检查请求的页面是否与/admin.jsp 模式匹配。如果是,hasRole('administrator') 将用作此页面的访问规则。所有其他页面将匹配/** 模式。由于所有经过身份验证的用户(包括administrator)都属于user 角色,因此所有其他页面都可供任何经过身份验证的用户使用。

    &lt;http&gt; 中不能使用多个&lt;form-login&gt;&lt;logout&gt; 标签。我也怀疑您是否可以在 Spring 配置中定义多个 &lt;http&gt; 部分。

    有关配置 Spring Security 的更多详细信息,请参阅Spring Security Reference

    更新

    另外,将default-target-url="/admin.jsp" 替换为default-target-url="/index.jsp",因为您不希望普通(非管理员)用户被重定向到admin.jsp

    【讨论】:

    • 我理解您所解释的概念并且我喜欢它,但是,当我按照您的概述进行操作时,我在浏览器中看到以下内容:“页面未正确重定向。Firefox 已检测到服务器正在以永远不会完成的方式重定向对该地址的请求。”当我访问默认 url 时,我被重定向到欢迎文件文件 (index.jsp),并且我可以在地址栏中看到我被重定向到 login.jsp。那是我在 Firefox 中看到错误的时候。
    • 只需将 更改为 解决了这个问题!
    【解决方案2】:

    尝试像这样使用“拒绝访问处理程序”:

    <http ...>
        ...
        <access-denied-handler error-page="the page you want to redirect to"/>
    </http>
    

    【讨论】:

    • 那么我应该使用两个单独的 元素,一个来定义需要保护的每个页面吗?如果是这样,我该如何解决“通用匹配模式...”异常?
    • 不,只有一个 元素,现在,您将获得您配置的错误页面,而不是“403 - 访问被拒绝错误”
    猜你喜欢
    • 2016-11-19
    • 2012-03-11
    • 2010-10-03
    • 2018-08-29
    • 2015-06-25
    • 1970-01-01
    • 1970-01-01
    • 2014-05-24
    相关资源
    最近更新 更多