2012-01-06 21 views
4

これはSpring Securityに関する質問です。私のアプリケーションでデフォルトの管理ユーザー(Spring 3、Spring Security)

、私は、ドメインオブジェクトとしてUserエンティティを持っています。ユーザーは登録され、データベースに格納された資格情報でログインします。私のUserドメインオブジェクトには、Spring UserDetailsオブジェクトをサポートする実装が含まれています。

課題は、私が最初のユーザーが作成される前でも、アプリケーションにログインする機能が必要だということです。つまり、「admin」ユーザーを作成するには、「admin」としてログインする必要があります。

私のSpringの設定が機能していることを確認するために、私は現在、SpringSecurityUserDetailsS​​erviceImpl.loadUserByUsername(String userName)からハードコードされた管理者を返しています。

public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException { 

    User user=null; 
    try { 
     if("admin".equalsIgnoreCase(userName)) { 
      user=new User(); 
      user.setUserName("ADMIN"); 
      user.setPassword("adsf"); // assume there's a hash of a true password here 
      user.setStatus(UserStatus.ACTIVE); 
      user.setAccessLevel(UserAccessLevel.ADMINISTRATOR); 
     } else { 
      //user = userDAO.getUserByUserName(userName); 

     } 

    } catch(Throwable t) { 
     throw new UsernameNotFoundException("Unable to locate User with user name \"" + userName + "\".", t); 
    } 

    return user; 
} 

これは動作しますので、今、私はそれを行うための正しい方法を探しています。 1つは、プロパティー・ファイルにこのデフォルトの管理ユーザーの信任状を定義し、loadUserByUsername(String userName)内のそのプロパティー・ファイルを読み取り、admnユーザー・オブジェクトを構成することです。しかし、私はSpring Security xmlの設定でこれを行う方法があることを願っています。私はsecurity:user name="admin" password="admin" authorities="ADMINISTRATOR"を試みたが、それは明らかにあなたが持っているときは動作しませんsecurity:authentication-provider user-service-ref="customUserDetailsService"

マイ春-のsecurity.xml

<security:http auto-config="true" use-expressions="true" access-denied-page="/denied"> 
<security:intercept-url pattern="/login.html" access="permitAll"/> 
<security:intercept-url pattern="/style/**" access="permitAll"/> 
<security:intercept-url pattern="/user**" access="hasRole('ADMINISTRATOR')"/> 
<security:intercept-url pattern="/**" access="hasRole('AUTHOR')"/> 

<security:form-login login-page="/login.html" 
         login-processing-url="/j_spring_security_check" 
         authentication-failure-url="/login.html?failedAttempt=true" 
         default-target-url="/home.html"/> 

<security:logout  invalidate-session="true" 
         logout-success-url="/login" 
         logout-url="/logout"/> 
         </security:http> 

<security:authentication-manager> 
    <security:authentication-provider user-service-ref="customUserDetailsService">  
     <security:password-encoder ref="passwordEncoder"/> 
    </security:authentication-provider> 
</security:authentication-manager> 

<bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder"/> 


<bean id="customUserDetailsService" class="com.modelsite.services.impl.SpringSecurityUserDetailsServiceImpl"/> 

そこで質問です:私は、ログインすることができ、デフォルトのadminユーザーを定義しますどのように、ものをする。注意してください、私はセットアップ時にsqlインポートでこれを処理したくありません。

答えて

3

あなたは、複数の認証プロバイダを持つことができます:あなたはすでに行ったよう

  • は、最初に使用します。
  • 管理者の固定名、パスワード、およびロールで秒を追加します。

(両方の認証プロバイダの順序は重要であり、認証が最初に発見されない場合は、2番目にのみ考慮される。)また、

<security:authentication-manager> 
    <security:authentication-provider user-service-ref="customUserDetailsService">  
     <security:password-encoder ref="passwordEncoder"/> 
    </security:authentication-provider> 
    <security:authentication-provider> 
     <security:user-service> 
      <security:user name="admin" password="admin" authorities="ROLE_USER, ROLE_ADMIN" /> 
     </security:user-service> 
    </security:authentication-provider> 
</security:authentication-manager> 

@see:Can I have multiple security contexts with spring security?

+0

ありがとう、Ralph。それは動作し、私の問題を解決します。 ''タグは私のためには機能しませんでしたが、セキュリティの名前空間 ''を使用してトリックを行いました。 – jacekn

+0

アプリケーションを使用してユーザーを作成した後で2番目の認証プロバイダを削除できない限り、これは非常に悪い考えで、常にadmin:adminユーザーを持つためです。 – aweigold

+0

@jacekn:私の誤り私はそれを訂正しました – Ralph

0

最初のユーザーが作成される前であっても、アプリケーションにログインする必要があります。つまり、「admin」ユーザーを作成するには、「admin」としてログインする必要があります。

私がこの問題を処理する方法は、私のカスタムUserDetailsServiceクラスおよび/またはそのDAOクラスにスマートを入れることです。空のユーザーの詳細テーブル(または何か)で起動されたことを検出すると、構成ファイルから読み込んだユーザーの詳細エントリによって初期化されます。本番システムのユーザーの詳細が自動化されたユニットとシステムテストのためのテストシステムのユーザ詳細ストアに

  • 負荷テストアカウントの束を保存するに

    • 負荷初期の管理者アカウント:これはにことができます。

    これが大変な場合は、管理コマンドに関連する行を挿入するSQL文を作成し、データベースの対話型SQLシェルを使用して実行してください。それが意味

    • (あなたはハッシュを使用しない限り)あなたのソースコードは、パスワードを見ることができる見ることができます誰でも、
    • :ので、あなたのソースコードに管理者アカウントを埋め込み


      は悪い考えです

    • これは、コードにという文字を追加しない限り、テストとプロダクションで同じパスワードを使用することを意味します(を追加しない限り)。

    これらはすべてセキュリティの問題を引き起こします。

  • +0

    スティーブンあなたの貢献に感謝します。組み込みの管理者アカウントは、Spring Securityの設定が機能していることを証明するためにここに表示されています。私はセッションを確立するのに苦労していると人々に考えさせたくありません。この質問は、はっきりと説明されたアカウントは行かなければならないと明言している。選択肢は、UserDetailsS​​erviceまたはSpring Securityの設定の中の「スマート」です。私の好みは後者のため、それゆえの質問です。 – jacekn

    1

    個人的には、管理者アカウントでは、基本的なSpring Securityユーザーサービスは使用しません。これは、主にDBベースのユーザー管理アプローチの柔軟性がないためです。実際には、推測や盗難、または単に忘れられる可能性があるため、管理者資格情報を一度確立することは望ましくありません。

    逆に、パスワードの回復に信頼できる電子メールアカウントを使用する場合は、管理者パスワードを含むすべてのアカウントに対してパスワード変更と回復のメカニズムを配置する必要があります。これは合理的な前提です。

    コンクリートを取得、私のアプローチは以下の通りである。 私は、次の

    @Service 
        public class CustomUserDetailsService implements UserDetailsService{ 
    
         @Autowired 
         @Qualifier("userDaoImpl") 
         private UserDao userDaoImpl; 
    
         @Override 
         @Transactional 
         public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException 
         { 
          User user = userDaoImpl.loadByUsername(username); 
          if (user != null) 
           return user; 
          else 
           throw new UsernameNotFoundException(username + " not found."); 
         } 
        } 
    

    これだけでなく、すべてのユーザーのために働くあるCustomUserDetailService

    <authentication-manager alias="authenticationManager"> 
         <authentication-provider user-service-ref="customUserDetailsService" > 
          <password-encoder ref="passwordEncoder" /> 
         </authentication-provider> 
        </authentication-manager> 
    
        <b:bean id="passwordEncoder" 
        class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" /> 
    

    を注入AuthenticationManagerを使用管理者

    が起動したときに管理者アカウントが完全に機能する問題が発生しました。これは、私が管理しなければならなかった理由です、@PostConstruct注釈は春が利用できるその取引サービスを持って保証するものではないことに注意してください、次の

    @Component 
        public class Initializer { 
    
         @Autowired 
         private HibernateTransactionManager transactionManager; 
         @Autowired 
         @Qualifier("userDaoImpl") 
         private UserDao userDao; 
         @Autowired 
         private CredentialsManager credentialsManager; 
    
         private String resetPassword = "makeItHardToGuess"; 
         private String adminUsername = "admin"; 
    
    
         @PostConstruct 
         private void init() 
         { 
          //since we are executing on startup, we need to use a TransactionTemplate directly as Spring may haven't setup transction capabilities yet 
          TransactionTemplate trxTemplate = new TransactionTemplate(transactionManager); 
          trxTemplate.execute(new TransactionCallbackWithoutResult() { 
           @Override 
           protected void doInTransactionWithoutResult(TransactionStatus status) { 
            buildAdmin(); 
           } 
          }); 
         } 
    
         private void buildAdmin() 
         {  
          //here I try to retrieve the Admin from my persistence layer 
          ProfiledUser admin = userDao.loadByUsername(adminUsername); 
    
          try 
          { 
           //If the application is started for the first time (e.g., the admin is not in the DB) 
           if(admin==null) 
           { 
            //create a user for the admin     
            admin = new ProfiledUser(); 
            //and fill her attributes accordingly 
            admin.setUsername(adminUsername); 
            admin.setPassword(credentialsManager.encodePassword(resetPassword)); 
            admin.setAccountNonExpired(true); 
            admin.setAccountNonLocked(true); 
            admin.setCredentialsNonExpired(true); 
            admin.setEnabled(true); 
            admin.setEulaAccepted(true); 
    
            Authority authority = new Authority(); 
            authority.setAuthority("ROLE_ADMIN"); 
            admin.getAuthorities().add(authority); 
           } 
           //if the application has previously been started (e.g., the admin is already present in the DB) 
           else 
           { 
            //reset admin's attributes 
            admin.setPassword(credentialsManager.encodePassword(resetPassword)); 
            admin.getAuthorities().clear(); 
            Authority authority = new Authority(); 
            authority.setAuthority("ROLE_ADMIN"); 
            admin.getAuthorities().add(authority); 
            admin.setAccountNonExpired(true); 
            admin.setAccountNonLocked(true); 
            admin.setCredentialsNonExpired(true); 
            admin.setEnabled(true); 
           }     
           userDao.save(admin); 
          } 
          catch (Exception e) 
          { 
           e.printStackTrace(); 
           System.out.println("Errors occurred during initialization. System verification is required."); 
          } 
         } 
        } 
    

    で詳細な、起動時に実行される初期 Beanを使用することによって達成されます私自身の取引。詳細はthisを参照してください。

    0

    答えはMaVVamaldoで、Initializerクラスとは別にクールです(既に+1しました)。そのクラスはデータベースを初期化するのに最適ですが、ソースコードを簡単に取得できるので安全ではない管理者の資格情報をハードコーディングすることは避けてください(最初の質問では避けるようにしています)。

    もっと良い解決策IMHOは、.propertiesファイル(chmodなどでアクセスを制限する)からハッシュされた認証情報を読み込むことです。このため はあなたのセキュリティのcontext.xml

    <authentication-manager> 
         <authentication-provider> 
          <password-encoder hash="sha"> 
           <salt-source user-property="username"/>  
          </password-encoder> 
          <user-service properties="classpath:/users.properties" /> 
         </authentication-provider> 
        </authentication-manager> 
    

    に次のように持っている必要があります動作するように。プロパティファイルには、次のようになります。あなたは、文字列explainedとしてpassword{username} 上で、それを計算するよう

    bob=4f393f2314f75650ee50844d8e4f016ab5b3468f,ROLE_ADMIN,enabled 
    

    塩はユーザー名です。

    関連する問題