0

基本的な春のセキュリティ D/B 認証プログラムを実行しようとしています。これを 2 つの方法で試しました。

方法 1 : Spring Security 認証にカスタム テーブルを使用する。
方法 2 : ユーザー認証と承認に Spring セキュリティ固有のデータベース テーブルを使用する。

ファイルの場所:
1. index.jsp -> webapp/index.jsp
2. welcome.jsp -> webapp/pages/welcome.jsp
3. login.jsp -> webapp/pages/login.jsp

方法 1 では、Spring セキュリティはリクエストをインターセプトせず、コンソールにエラーが表示されませんでした。リクエストをインターセプトする代わりに、welcome.jsp に直接移動しました。

PS - 認証を試みていなかったので、セキュリティ コンテキスト xml で以下の「authorities-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」という名前でスプリング固有のデータベース テーブルを作成しました。ここでは、以下に示すように xml で SQL クエリが使用されていません。

 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データベースを使用しています。

[更新]:両方の方法でエラーの根本原因を見つけるために、Spring デバッグ ロギングを有効にしました。ログから正確に何が問題なのかを把握または理解できなかったので、両方の方法を試した後に取得したログを比較しました。方法 1 の場合、Spring セキュリティはリクエストをインターセプトせず、方法 2 の場合はログインできました (Spring セキュリティは少なくともリクエストを傍受しています)が、正しいユーザー名とパスワードを入力した後でも、「資格情報が正しくありません」というメッセージが表示されました。

以下は、方法 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 では、「承認」用のカスタム テーブルを作成した後に、「authorities-by-username-query」タグを追加しました。今、私はログイン画面を取得しているので、春のセキュリティがインターセプトするためには、「authorities-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」テーブルをフォローしています:

ユーザー ID 整数

ユーザー名 VARCHAR2 (50 バイト)

パスワード VARCHAR2 (50 バイト)

有効な整数

「users_detail」テーブルのデータ:

USER_ID ユーザー名 パスワード有効

100 ユーザー 123456 1

私のクエリは security-context.xml にあります:

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

クエリを手動で実行するとき、つまりusername = 'user'のusers_detailからusername、password、enabledを選択します。結果セットを取得します。

どこが間違っていますか?D/B に同じエントリがあるにもかかわらず、JdbcUserDetailsManager クラスが常に「クエリはユーザー 'user' の結果を返しませんでした」を返すのはなぜですか。

デバッグ モードでは、上記のエラーが発生したときに JdbcUserDetailsManager クラスのどのメソッドが実行されているかが表示されません。どうすればそれを知ることができますか? また、パスワードフィールドを保存する際に、スプリングは内部的に暗号化/復号化技術を実行しますか?

4

1 に答える 1

0

デフォルトのスキーマを使用している場合、ログ メッセージ「User 'admin' not found」は認証失敗の理由として非常に明確に見えます。コマンドを手動で実行して、ユーザーデータが返されるかどうかを確認してみませんか?

また、ログイン画面が表示されるかどうかは、「ユーザー名ごとの権限」の設定の有無に依存しません。intercept-url要求する URL にどの値が適用されるかによってのみ異なります。唯一の例外は、(権限が不十分な認証済みユーザーの) アクセス拒否動作をカスタマイズして、ログイン ページを表示する場合です (ここではそうではありません)。

SQL 例外は、カスタム テーブルの列の型が間違っていることが原因である可能性があります。標準スキーマから取得した結果セットと互換性のあるものにする必要があります。よほどの理由がない限り、デフォルトのままにしておくことをお勧めします。

さらに良いことに、HSQLDB のような単純なテスト データベースで基本的な操作ができるようになるまで、Oracle のことは完全に忘れてください。

于 2013-03-29T14:45:50.213 に答える