2013-03-27 178 views
0

我試圖做一個基本的Spring Security d/B認證program.I通過兩種方式即春季安全不攔截請求

方法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中使用'authorities-by-username-query'屬性。我不確定是否強制創建授權表。

下面是我的安全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,則i創建以下下面的鏈接之後在「USERS」和「權威」的名稱特定的彈簧數據庫表。這裏,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> 

當我試圖用上述方法,即使我輸入正確的用戶名密碼&,我是越來越「壞憑據」的消息[但是,是的,在這種情況下,春季安全攔截了請求。我正在使用Oracle數據庫。

[更新]:我啓用了彈簧調試日誌記錄,以在兩種方法中查找錯誤的根本原因。我無法弄清楚或明白從日誌中究竟發生了什麼錯誤,所以我比較了在嘗試這兩種方法後得到的日誌。至於方法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.sprin[email protected]9055c2bc: Principal: anonymousUser; Credentials: 

     [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]b364: 

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

     [email protected], returned: -1 
     DEBUG: org.springframework.security.access.vote.AffirmativeBased - Voter: 

     [email protected]bc, 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.sprin[email protected]6fa8940c: Principal: 

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

     org.sprin[email protected]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.se[email protected]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,我增加了「主管部門按用戶名查詢」標籤在爲'授權'創建自定義表之後。現在我就在登錄界面,所以我得到序知道春天安全攔截我需要有「機關按用戶名查詢」標籤。但輸入用戶名和密碼後,我獲得以下錯誤mesage:

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.se[email protected]e7736c 
     DEBUG: org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler - Redirecting to /loginfailed.html 
     DEBUG: org.springframework.security.web.DefaultRedirectStrategy - Redirecting to '/itrade-web/loginfailed.html' 

[更新]:現在對於這兩種方法我得到同樣的錯誤,雖然我輸入正確的用戶名& password.Also,因爲我可以從獲取數據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密碼啓用

100用戶123456 1

我的查詢是安全的context.xml:當我執行用戶名,密碼,從users_detail啓用

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

手動選擇即查詢其中username ='user'。我得到結果集。

我在哪裏去了?爲什麼JdbcUserDetailsManager類總是返回'查詢不返回用戶'用戶的結果'',即使D/B中有相同的條目。

調試模式不顯示當我得到上述錯誤正在執行哪個JdbcUserDetailsManager類的方法。我怎麼知道?另外,spring是否在保存密碼字段的同時執行任何加密/解密技術?使用默認模式時

+0

你的問題太長了...但這裏是我的猜測:對於方法1,intercept-url你沒有access =「authenticated」。沒有它,任何請求都不會被過濾。 – 2013-03-28 07:15:53

+0

@HoàngLong - 如果我補充說我在啓動服務器時得到下面的異常。引起:java.lang.IllegalArgumentException:不支持的配置屬性:[authenticated] ... – coder87 2013-03-28 09:58:41

+0

也許你可以檢查http://stackoverflow.com/questions/2527198/spring-security-notation-for-is-authenticated-fully。在這個問題中,他們引用其他兩種方法來保護URL:使用isAuthenticated()和IS_AUTHENTICATED_FULLY。也許其中一個會爲你解決。 – vincentks 2013-03-28 17:20:06

回答

0

日誌消息「用戶‘管理員’未找到」似乎爲理由,認證失敗,很清楚。爲什麼不手動執行命令並查看它是否返回用戶數據?

另外,登錄屏幕是否顯示並不取決於是否設置「「當局按用戶名查詢」與否。它僅取決於您請求的網址是否適用於intercept-url值。唯一的例外是,如果您已經自定義訪問被拒絕的行爲(對於沒有足夠權限的經過驗證的用戶)來顯示登錄頁面(這裏不是這種情況)。

您的SQL異常可能是由於您的自定義表具有錯誤的列類型。您需要結束與從標準模式獲得的結果集兼容的內容。除非你有充分的理由不這樣做,否則更好地堅持默認。

更好的是,完全忘記Oracle,直到您可以使用像HSQLDB這樣的簡單測試數據庫來處理基本知識。

+0

感謝您的答覆。對於SQL異常,我搜索並知道它可能是因爲列類型,所以後來將列類型更改爲常規列,就像所有示例代碼中那樣,即使用用戶名,密碼,已啓用的列工作。是否必須創建一個包含'userid','username',密碼,已啓用列的表?不能我創建任何其他列/列類型的表。不知道爲什麼spring不會將oracle類型轉換爲相應的jdbc類型以避免此錯誤。對於「用戶'管理員'找不到」我非常肯定,D/B有這些數據,因爲我可以沒有任何問題地獲取。 – coder87 2013-03-29 15:42:41

+0

在JdbcUserDetailsManager類中,我可以看到'validateAuthorities'檢查權限的方法。所以我認爲可能會春天授權我們訪問,也因爲它包括「'權限 - 用戶名 - 查詢」標籤後工作。我不確定,但當'validateAuthorities'方法被調用時,請在這裏糾正我,如果我錯了。 – coder87 2013-03-29 15:54:46

+0

默認模式在[手冊](http://static.springsource.org/spring-security/site/docs/3.1.x/reference/springsecurity-single.html)中定義。您可以添加其他人,但您需要相應地自定義查詢。你會發現編寫一個自定義UserDetailsS​​ervice和添加額外的屬性,如果你搜索的信息。如果您的查詢返回與結果集預期不同的類型,那麼它將失敗。我猜想這很可能與Oracle和布爾值有關。 – 2013-03-29 15:59:52