2013-03-27 179 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