6

私はこの問題をSpringBootとSpringBoot-Securityを使ってカスタムログイン認証を実装しています。このスレッドの参考にしました(CustomSecuringWeb branch内)Bitbucket repositoryを作成しました。他の何よりも先にコメントのほとんどはSecuring a Web Applicationのチュートリアルに続きます。カスタムWebSecurityConfigurerAdapter

私は、認証データが、単に生産ラインアプリケーションでは非常に一般的なメモリデータではなく、データベースからどのようになったのか不思議でした。

私は2つの試行を行いましたが(どちらの試行も同じブランチにありますが、はそれがと悪いです)。カスタムUserDetailsService実装に問題がある、私は知らないカスタムAbstractUserDetailsAuthentictionProvider実装

を作成し

  • を作成し

    1. が、コンソールログをチェックすると、両方返す持続性(でもリポジトリ)各カスタムクラスのDI(nullの場合)

      問題はどうやって両方の試みを動作させることができるかです。そして、2つの試みのどちらが他のものより優れているか(おそらく)。

  • +1

    あなたのbitbucketリンクは無効です –

    答えて

    10

    まず、2つのアプローチは異なる目的で使用されており、互換性がありません。

    ケース1:

    UserDetailsServiceは、ユーザーを認証あなたの認証でユーザー情報を検索するDAOとして純粋に使用し、その情報に基づいており、認証はUserDetailsService、単にデータアクセス内で行われるべきではありません。 仕様にはっきりと記載されています。これはあなたが探しているものです。

    ケース2:あなたは、あなたが行うことができ、カスタムのログイン名とパスワード以外の分野で認証する場合

    AuthentictionProvider一方では、例えば、認証のカスタムメソッドを提供するために使用されるAuthentictionProviderを実装し、このオブジェクトを供給することにより、 AuthenticationManagerBuilderに私はこれがあなたのプロジェクトでやりたいことだとは思わない。デフォルトの方法であるログインとパスワードを使用して、データベースに格納されたユーザーに基づいて認証を実装しようとしているだけです。上記で ケースあなただけUserDetailsServiceAuthentictionProviderのインスタンスはコンテナによってAuthenticationManagerであなたのために作成された、あなたは認証用のユーザーをretriveするために使用されているシステムでは何もなく、DAOではありませんUserDetailsS​​erviceを供給するので、それはDaoAuthenticationProviderをした実装1 。お使いの設定であなたの実装に今

    、 の代わりに:

    @Override 
        protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
    //  auth.userDetailsService(new AdminSecurityService()); 
         auth.authenticationProvider(new AdminSecurityAuthenticationProvider()); 
        } 
    

    はもちろんのorg.springframework.security.core.userdetails.UserDetailsService

    @Service 
    public class CustomUserDetailsService implements UserDetailsService { 
    
        private final AdminRepository userRepository; 
    
        @Autowired 
        public CustomUserDetailsService(AdminRepository userRepository) { 
         this.userRepository = userRepository; 
        } 
    
        @Override 
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 
         Admin user = userRepository.findByLogin(username); 
         if (user == null) { 
          throw new UsernameNotFoundException(String.format("User %s does not exist!", username)); 
         } 
         return new UserRepositoryUserDetails(user); 
        } 
    
        private final static class UserRepositoryUserDetails extends Admin implements UserDetails { 
    
         private static final long serialVersionUID = 1L; 
    
         private UserRepositoryUserDetails(User user) { 
          super(user); 
         } 
    
         @Override 
         public Collection<? extends GrantedAuthority> getAuthorities() { 
          return AuthorityUtils.createAuthorityList("ROLE_USER"); 
         } 
    
         @Override 
         public String getUsername() { 
          return getLogin();//inherited from user 
         } 
    
         @Override 
         public boolean isAccountNonExpired() { 
          return true;//not for production just to show concept 
         } 
    
         @Override 
         public boolean isAccountNonLocked() { 
          return true;//not for production just to show concept 
         } 
    
         @Override 
         public boolean isCredentialsNonExpired() { 
          return true;//not for production just to show concept 
         } 
    
         @Override 
         public boolean isEnabled() { 
          return true;//not for production just to show concept 
         } 
    //getPassword() is already implemented in User.class 
        } 
    
    } 
    

    を実装しており、この

    @Autowired 
    private CustomUserDetailsService userDetailsService; 
    
    @Override 
    protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
        auth.userDetailsService(userDetailsService); 
    
    } 
    

    とあなたのCustomUserDetailsServiceような何かを行います実装が上がっている取得したユーザー(あなたの場合はAdmin.class)に基づいて、そのユーザーのパスワードとそのインターフェイスの残りのメソッドを提供する必要があります。それが役に立てば幸い。私はこの例を実行していないので、いくつかのタイプミスをして、何かがうまくいかないかどうか尋ねてみましょう。私はまたあなたがそれを必要としない場合は、あなたのプロジェクトから 'AuthentictionProvider'を取り除くでしょう。コメントの後http://docs.spring.io/spring-security/site/docs/4.0.0.RC1/reference/htmlsingle/#tech-userdetailsservice

    ここでは、ドキュメントを得た をあなただけやるあまり手間をかけずにあなたのconfigureメソッドでPasswordEncoderを設定することができます。あなたがアクセスを取得するので

    @Override 
    protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder); 
    
        } 
    @Bean 
        public PasswordEncoder passwordEncoder(){ 
         PasswordEncoder encoder = new BCryptPasswordEncoder(); 
         return encoder; 
        } 
    

    をあなたはそれを行うことができますAbstractDaoAuthenticationConfigurerauth.userDetailsService(userDetailsService)から返され、の使用を選択した場合は、DaoAuthenticationProviderを設定することができます。 あなたはPasswordEncoderAuthenticationProviderに設定されている権利ですが、あなただけのauth.userDetailsService(userDetailsService)から返されconvineinceオブジェクトを使用し、すでにあなたのために作成されたあなたのケースDaoAuthenticationProviderAuthenticationPrioviderに渡します、そのオブジェクト上のエンコーダを設定AuthenticationProviderを実装 する必要はありません。 コメントに記載されているロードランナーのように、ごくまれに独自に実装する必要があるのは、AuthenticationProviderです。AbstractDaoAuthenticationConfigurerを使用して認証設定の調整をほとんど行うことができます。から返されます。

    "パスワードの暗号化を追加したかったのですが、ユーザーがロックされているかどうかを確認したり、ユーザーがまだログインしていないかどうかなど(パスワードハッシュを除く) )は、AuthenticationProviderを使用します。

    あなたは上記の方法のいずれかを返す場合はfalse認証が失敗することがわかりますUserDetailsインターフェースを見ればありません、これは標準の認証メカニズム http://docs.spring.io/autorepo/docs/spring-security/3.2.0.RELEASE/apidocs/org/springframework/security/core/userdetails/UserDetails.html の一環として、あなたのために行われます。 非常に非標準的なケースでは、AuthenticationProviderの実装が本当に必要です。すべての標準的なものは、フレームワークによってかなり覆われています。

    +0

    私は参照してください。基本的に 'UserDetailsS​​ervice'を使って' username'パラメータを使ってユーザの詳細を取得します。パスワード暗号化を追加したいと思ったことがありましたら。また、他の認証(ユーザがロックされているかどうかのチェック、アクティブ、ユーザがまだログインしていないなど[パスワードハッシュを除く])を実行する場合は、AuthenticationProviderを使用します。 –

    +0

    パスワードの暗号化が必要な場合は、カスタムのPasswordEncoderインスタンスを作成して、どちらのケースにも含めるようにします。 –

    +0

    いいえ、既にSpring Securityで利用可能な 'AuthenticationProvider'と' PsswordEncoder'インターフェースの両方の実装が非常に優れています。 99%のケースであなた自身で実装するべきではありません。また、これは元の質問の範囲外です。参考資料を読むか、別の質問をしてください。 – Roadrunner

    1

    JDBCの場合、http://www.mkyong.com/spring-security/spring-security-form-login-using-database/では、基本的にユーザーを取得するためにクエリを指定する必要があります。

    +0

    これは簡単な解決策です。しかし、すべてのパスワードに関連するフィールド用のカスタムパスワードエンコーダを作成したい場合はどうでしょうか。 –

    +0

    PasswordEncoderはパスワードのエンコード/デコードを行います。エンコーダは、このメソッドでDAOで指定できます。_auth.jdbcAuthentication()。dataSource(dataSource).passwordEncoder()_; – sebge2

    +0

    しかし、jdbcAuthentication(つまり、SessionAuthentication - ユーザーがまだログインしていないかどうかを確認する)以外にカスタム認証を作成する場合はどうすればよいですか? –

    1

    まず、String Security Core Servicesについて読むことをお勧めします。

    この状況の最も重要なものは、ユーザーが認証されているかどうかを判断する責任を負うAuthenticationManagerです。これはAuthenticationManagerBuilderで設定します。 Springの主な実装はProviderManagerで、単一のアプリケーションで複数の認証メカニズムを定義できます。最も一般的な使用例は1つありますが、それでもこのクラスで処理されます。これらの複数の認証メカニズムのそれぞれは、異なるAuthenticationProviderによって表されます。ProviderManagerAunthenticationProvidersのリストを取得し、その中から反復していずれかがユーザーを認証できるかどうかを確認します。

    あなたが興味を持っているものはDaoAuthenticationProviderです。名前が示すように、データアクセスオブジェクトを使用してユーザーを認証することができます。このようなDAOのための標準インタフェースを使用しています - UserDetailsService。 Spring Securityにはデフォルト実装が用意されていますが、通常これは実装したいビットです。残りはすべて提供されます。

    また、必要なコンフィギュレーションビットは、SpringBootから完全に独立しています。これは、あなたがXMLでそれを行うだろうかです:

    <sec:authentication-manager > 
        <sec:authentication-provider user-service-ref="myUserDetailsService" /> 
    </sec:authentication-manager> 
    

    とJavaで、それは次のようになります。UserDetails実装あたりとして

    @Configuration 
    @EnableWebSecurity 
    public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { 
    
        @Autowired 
        private UserDetailsService myUserDetailsService; 
    
        @Override 
        protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
         auth.userDetailsService(myUserDetailsService); 
        } 
    } 
    

    、通常the one provided by Spring Securityは十分にあります。しかし、必要に応じて自分自身を実装することもできます。

    通常、PasswordEncoderも必要です。 BCryptPasswordEncoderのような良いもの、:あなたはデータベースに保存して、ユーザーのパスワードをエンコードするために、あなたのUserRepositoryでそれを@Autowireことができるように、それは、@Beanだと

    @Configuration 
    @EnableWebSecurity 
    public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { 
    
        @Autowired 
        private UserDetailsService userDetailsService; 
    
        @Autowired 
        private PasswordEncoder passwordEncoder; 
    
        @Bean 
        public PasswordEncoder passwordEncoder() { 
         return new BCryptPasswordEncoder(); 
        } 
    
        @Override 
        protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
         auth.userDetailsService(userDetailsService) 
          .passwordEncoder(passwordEncoder); 
        } 
    } 
    

    は注意してください。

    +0

    のXML構成を削除する方法はありますか? –

    +0

    これは別の方法です。 XMLまたはJavaで実行できます。私は両方の方法を示しました。あなたは一度に両方をやってはいません - ただ一つです。 – Roadrunner

    関連する問題