Spring安全没有拦截请求

时间:2013-03-27 16:06:11

标签: spring spring-mvc spring-security

我正在尝试做一个基本的弹簧安全D / B认证程序。我试过两种方式,即

方法1:使用自定义表进行Spring Security身份验证 方法2:使用Spring特定于安全性的数据库表进行用户身份验证和授权。

文件位置:
1. index.jsp - > Web应用程序/ index.jsp的
2. welcome.jsp - > Web应用程序/网页/的welcome.jsp
3. login.jsp - > web应用程序/网页/ login.jsp的

对于方法1,Spring安全性没有拦截请求,我没有在控制台中看到错误。而不是拦截请求,我直接被带到welcome.jsp。

P.S - 由于我没有尝试授权,我没有在安全上下文xml中使用下面的“authority-by-username-query”属性。我不确定是否必须创建一个授权表。

以下是我的security-context.xml:

<?xml version="1.0" encoding="UTF-8"?>
     <beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:tx="http://www.springframework.org/schema/tx"
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-3.1.xsd
      http://www.springframework.org/schema/tx 
      http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

<security:http auto-config="true">
    <security:intercept-url pattern="/welcome.html" />
    <security:form-login login-page="/login.html"
        default-target-url="/welcome.html" authentication-failure-url="/loginfailed.html" />
    <security:logout logout-success-url="/logout.html" />
</security:http>

<security:authentication-manager>
    <security:authentication-provider>
        <security:jdbc-user-service data-source-ref="dataSource"
         users-by-username-query="select FIRST_NAME,LAST_NAME,PASSWORD from USER_AUTHENTICATION where FIRST_NAME=?" />
    </security:authentication-provider>
</security:authentication-manager>

的web.xml:

 <?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-  app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
 <display-name>SpringPOC</display-name>
 <servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
        /WEB-INF/applicationContextDirect.xml
        /WEB-INF/applicationContext-security.xml
    </param-value>
</context-param>
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
  <filter-name>springSecurityFilterChain</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

BaseController

//@RequestMapping(value="/login", method = RequestMethod.GET)
@RequestMapping("/login")
public ModelAndView login(Model model) {
    //System.out.println("Inside /login...");
    return new ModelAndView("login");
}
/*public String login(ModelMap model) {

    System.out.println("Inside /login...");
    return "login";

}*/

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

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

}

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

    return "login";

}

的login.jsp

    <%@ 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 (Authentication with Database)</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 colspan='2'><input name="reset" type="reset" />
                </td>
            </tr>
        </table>

    </form>

的index.jsp

    <body>
    <div id="content">
   <h1>Home Page</h1>
   <p>
   Anyone can view this page.
   </p>
   <p><a href="welcome.html">Login page</a></p>
   </div>
   </body>

对于方法2,我按照以下链接创建了名为“USERS”和“AUTHORITIES”的春季特定数据库表。这里的SQL查询不在xml中使用,如下所示。

 http://www.raistudies.com/spring-security-tutorial/authentication-authorization-spring-security-mysql-database/

除了security-context.xml之外,每件事都保持不变。

  <?xml version="1.0" encoding="UTF-8"?>
  <beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:tx="http://www.springframework.org/schema/tx"
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-3.1.xsd
      http://www.springframework.org/schema/tx 
      http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

<security:http realm="Project Realm" auto-config="true">
    <security:intercept-url pattern="/welcome.html" access="ROLE_USER"/>
    <security:form-login login-page="/login.html"
        default-target-url="/welcome.html" authentication-failure-url="/loginfailed.html" />
    <security:logout logout-success-url="/logout.html" />   
</security:http>

<security:authentication-manager>
    <security:authentication-provider>
    <security:password-encoder hash="md5"/>
    <security:jdbc-user-service data-source-ref="dataSource"/>
    </security:authentication-provider>
</security:authentication-manager>
    </beans>

当我尝试上述方式时,即使我输入了正确的用户名&amp;密码,我得到'坏凭据'消息[但是,在这种情况下,春天安全正在拦截请求]。我正在使用Oracle数据库。

[更新]:我启用了spring调试日志记录,以找出两种方法中错误的根本原因。我无法弄清楚或理解日志究竟出了什么问题,所以我比较了我在尝试这两种方法后得到的日志。对于方法1,Spring安全性没有拦截请求,而方法2我能够登录(Spring安全性是至少拦截请求)但即使在输入正确的用户名后,我仍然收到“Bad credential”消息密码。

以下是方法2的代码片段[这里我获取登录页面,但身份验证失败]

            firing Filter: 'FilterSecurityInterceptor'
        DEBUG: org.springframework.security.web.util.AntPathRequestMatcher - Checking match of request : '/welcome.html'; against 

        '/welcome.html'
        DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: 

        /welcome.html; Attributes: [ROLE_USER]
        DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Previously Authenticated: 

        org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Credentials: 

        [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: 

        RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
        DEBUG: org.springframework.security.access.vote.AffirmativeBased - Voter: 

        org.springframework.security.access.vote.RoleVoter@19432e0, returned: -1
        DEBUG: org.springframework.security.access.vote.AffirmativeBased - Voter: 

        org.springframework.security.access.vote.AuthenticatedVoter@9830bc, returned: 0
        DEBUG: org.springframework.security.web.access.ExceptionTranslationFilter - Access is denied (user is anonymous); 

        redirecting to authentication entry point
        org.springframework.security.access.AccessDeniedException: Access is denied
            at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83)
            at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation

        (AbstractSecurityInterceptor.java:206)
            at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke

        (FilterSecurityInterceptor.java:115)
            at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter

        (FilterSecurityInterceptor.java:84)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
            at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
            at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
            at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter

        (AnonymousAuthenticationFilter.java:113)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
            at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter

        (SecurityContextHolderAwareRequestFilter.java:54)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
            at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
            at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter

        (BasicAuthenticationFilter.java:150)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
            at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter

        (AbstractAuthenticationProcessingFilter.java:183)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
            at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
            at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter

        (SecurityContextPersistenceFilter.java:87)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
            at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
            at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
            at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
            at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
            at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
            at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
            at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
            at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
            at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857)
            at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
            at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
            at java.lang.Thread.run(Thread.java:662)
        DEBUG: org.springframework.security.web.savedrequest.HttpSessionRequestCache - DefaultSavedRequest added to Session: 

        DefaultSavedRequest[http://localhost:8080/itrade-web/welcome.html]
        DEBUG: org.springframework.security.web.access.ExceptionTranslationFilter - Calling Authentication entry point.
        DEBUG: org.springframework.security.web.DefaultRedirectStrategy - Redirecting to 'http://localhost:8080/itrade-

        web/login.html;jsessionid=3FD72892F4F4EF2E65B0C90ABE115354'
        DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - SecurityContext is empty or contents 

        are anonymous - context will not be stored in HttpSession.
        DEBUG: org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as 

        request processing completed
        DEBUG: org.springframework.security.web.FilterChainProxy - /login.html at position 1 of 10 in additional filter chain; 

        firing Filter: 'SecurityContextPersistenceFilter'
        DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - HttpSession returned null object for SPRING_SECURITY_CONTEXT
        firing Filter: 'UsernamePasswordAuthenticationFilter'
        ...
        DEBUG: org.springframework.security.web.FilterChainProxy - /login.html at position 7 of 10 in additional filter chain; 

        firing Filter: 'AnonymousAuthenticationFilter'
        DEBUG: org.springframework.security.web.authentication.AnonymousAuthenticationFilter - Populated SecurityContextHolder with 

        anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@6fa8940c: Principal: 

        anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: 

        org.springframework.security.web.authentication.WebAuthenticationDetails@fffde5d4: RemoteIpAddress: 0:0:0:0:0:0:0:1; 

        SessionId: 3FD72892F4F4EF2E65B0C90ABE115354; Granted Authorities: ROLE_ANONYMOUS'
                    ...
        DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Request is to process 

        authentication
        DEBUG: org.springframework.security.authentication.ProviderManager - Authentication attempt using 

        org.springframework.security.authentication.dao.DaoAuthenticationProvider
        DEBUG: org.springframework.security.provisioning.JdbcUserDetailsManager - Query returned no results for user 'admin'
        DEBUG: org.springframework.security.authentication.dao.DaoAuthenticationProvider - User 'admin' not found
        DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Authentication request 

        failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
        DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Updated SecurityContextHolder 

        to contain null Authentication
        DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Delegating to authentication 

        failure handler org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler@1882c1a
        DEBUG: org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler - Redirecting to 

        /loginfailed.html
        DEBUG: org.springframework.security.web.DefaultRedirectStrategy - Redirecting to '/itrade-web/loginfailed.html'
        DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - SecurityContext is empty or contents 

        are anonymous - context will not be stored in HttpSession.
        DEBUG: org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as 

        request processing completed

[更新]对于方法1,我在为“授权”创建自定义表后添加了“authority-by-username-query”标记。现在我正在登录屏幕,所以我知道为了春天安全拦截我需要'authority-by-username-query'标签。但是输入用户名和密码后我得到以下错误信息:

 Caused : PreparedStatementCallback; uncategorized SQLException for SQL [select          FIRST_NAME,LAST_NAME,PASSWORD from USER_AUTHENTICATION where FIRST_NAME=?]; SQL state   [null]; error code [17059]; Fail to convert to internal representation; nested exception is   java.sql.SQLException: Fail to convert to internal representation 

我在调试模式中看到以下几行:

            DEBUG: org.springframework.security.authentication.ProviderManager - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
        INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
        DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Authentication request failed: org.springframework.security.authentication.AuthenticationServiceException: PreparedStatementCallback; uncategorized SQLException for SQL [select FIRST_NAME,LAST_NAME,PASSWORD from USER_AUTHENTICATION where FIRST_NAME=?]; SQL state [null]; error code [17059]; Fail to convert to internal representation; nested exception is java.sql.SQLException: Fail to convert to internal representation
        DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Updated SecurityContextHolder to contain null Authentication
        DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Delegating to authentication failure handler org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler@e7736c
        DEBUG: org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler - Redirecting to /loginfailed.html
        DEBUG: org.springframework.security.web.DefaultRedirectStrategy - Redirecting to '/itrade-web/loginfailed.html'

[更新]:现在,对于这两种方法,虽然我输入了正确的用户名,但我得到了同样的错误。密码。此外,因为我可以从D / B获取数据,我确信我没有出错,因为D / B中没有数据。

 DEBUG: org.springframework.security.provisioning.JdbcUserDetailsManager - Query returned no results for user 'user'

我觉得这个错误背后应该有任何其他原因。

[编辑]现在我跟随D / B中的'users_detail'表:

USER_ID INTEGER

USERNAME VARCHAR2(50字节)

PASSWORD VARCHAR2(50字节)

ENABLED INTEGER

'users_detail'表格中的数据:

USER_ID USERNAME PASSWORD ENABLED

100位用户123456 1

我的查询在security-context.xml中:

  "select username,password, enabled from users_detail where username=?"

当我手动执行查询时,即选择用户名,密码,从users_detail启用,其中username ='user'。我得到了结果集。

我哪里错了?为什么JdbcUserDetailsManager类总是返回'查询返回没有结果用户'用户'',即使在D / B中有相同的条目。

当我收到上述错误时,调试模式不显示正在执行JdbcUserDetailsManager类的哪个方法。我怎么知道的?另外,Spring在保存密码字段时是否在内部执行任何加密/解密技术?

1 个答案:

答案 0 :(得分:0)

使用默认架构时,日志消息“找不到用户'admin'似乎非常清楚,这是导致身份验证失败的原因。为什么不手动执行命令并查看它是否返回用户数据?

此外,是否显示登录屏幕并不取决于您是否设置了“'authority-by-username-query”。它仅取决于您请求的URL是否适用intercept-url个值。唯一的例外是,如果您已经定制了访问被拒绝的行为(对于权限不足的经过身份验证的用户)来显示登录页面(这里不是这种情况)。

您的SQL异常可能是由于您的自定义表具有错误的列类型。您需要最终得到与从标准模式获得的结果集兼容的内容。最好坚持使用默认值,除非你有充分的理由不这样做。

更好的是,完全忘记Oracle,直到您可以使用简单的测试数据库(如HSQLDB)来完成基础知识。