2016-03-10 5 views
8

私はSpring Boot(1.2.7.RELEASE)とVaadin(7.6.3)に基づいてアプリケーションを構築しようとしています。私の問題は、Spring SecurityとVaadinを統合できないことです。私はカスタムVaadinのLoginScreenとSpring Securityコントロールを構築したい。次のように私のプロジェクトのセットアップは次のとおりです。Vaadinログインによるスプリングブートセキュリティ

@Configuration 
@EnableWebSecurity 
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http.csrf().disable(). 
       exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")).accessDeniedPage("/accessDenied") 
       .and().authorizeRequests() 
       .antMatchers("/VAADIN/**", "/PUSH/**", "/UIDL/**", "/login", "/login/**", "/error/**", "/accessDenied/**", "/vaadinServlet/**").permitAll() 
       .antMatchers("/authorized", "/**").fullyAuthenticated(); 
    } 
} 

そして、ここでは私のVaadinのログインUIである

@SpringUI(path = "/login") 
    @Title("LoginPage") 
    @Theme("valo") 
    public class LoginUI extends UI { 

     TextField user; 
     PasswordField password; 
     Button loginButton = new Button("Login", this::loginButtonClick); 
     private static final String username = "username"; 
     private static final String passwordValue = "test123"; 

     @Override 
     protected void init(VaadinRequest request) { 
      setSizeFull(); 

      user = new TextField("User:"); 
      user.setWidth("300px"); 
      user.setRequired(true); 
      user.setInputPrompt("Your username"); 

      password = new PasswordField("Password:"); 
      password.setWidth("300px"); 
      password.setRequired(true); 
      password.setValue(""); 
      password.setNullRepresentation(""); 

      VerticalLayout fields = new VerticalLayout(user, password, loginButton); 
      fields.setCaption("Please login to access the application"); 
      fields.setSpacing(true); 
      fields.setMargin(new MarginInfo(true, true, true, false)); 
      fields.setSizeUndefined(); 

      VerticalLayout uiLayout = new VerticalLayout(fields); 
      uiLayout.setSizeFull(); 
      uiLayout.setComponentAlignment(fields, Alignment.MIDDLE_CENTER); 
      setStyleName(Reindeer.LAYOUT_BLUE); 
      setFocusedComponent(user); 

      setContent(uiLayout); 
     } 

     public void loginButtonClick(Button.ClickEvent e) { 
      //authorize/authenticate user 
      //tell spring that my user is authenticated and dispatch to my mainUI 
     } 

    } 

私が起動すると私のアプリケーションスプリングは結構です、私のログインUI、に私をリダイレクトします。

しかし、私は春のセキュリティメカニズムと私のmainUIへのディスパッチに対してユーザーを認証する方法がわかりません。

また、私はCSRFを無効にしない場合、私は症例報告書のトークンがnull例外ではあり得るでしょう、CSRFトークンとの問題に直面しています。私はこれらの問題を扱う多くの例を見つけましたが、Vaadinで提供されるソリューションはありません。

ありがとうございました。

+1

私はVaadin + Spring Boot + Spring Securityを使用したアプリケーションの実際の例を持っていますが、残念ながらこの例はまだ文書化されていません。しかし、おそらくあなたの仕事のためのコードからいくつかのインスピレーションを得ることができます:https://github.com/rolandkrueger/vaadin-by-example/tree/master/en/architecture/SpringBootSecurity –

+0

ちょっとローランド、私はあなたのプロジェクトを見てきましたそれは多くの助けとなりました。それを共有してくれてありがとう。 –

+0

あなたの質問に実際に答えなくてもうれしいです;-) –

答えて

20

1週間の闘争と研究の後、私はこれを得ることができました。インターネット上には多くの情報とソリューションがあり、そのほとんどはxmlベースの設定やJSPフォームベースのログインを使用しています。これまで、Vaadinフレームワークを使用してXML設定ファイルを使用せずに別のソリューションを見つけることができませんでしたカスタムログインページ。

これがベストプラクティスまたは最も簡単な解決策であるとは限りません。さらに、私はそれのすべての部分を評価しなかった、ログイン機構は私が見ることができる限り動作するが、おそらく私がまだ発見していないいくつかの問題があるかもしれない。

多分、同じ問題に直面している人を助けるでしょう。私は答えをここに掲示します。すべての私のsecurityConfigの

まず:

@Resource(name = "authService") 
private UserDetailsService userDetailsService; 

@Override 
protected void configure(HttpSecurity http) throws Exception { 
       http.csrf().disable(). 
         exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")).accessDeniedPage("/accessDenied") 
         .and().authorizeRequests() 
         .antMatchers("/VAADIN/**", "/PUSH/**", "/UIDL/**", "/login", "/login/**", "/error/**", "/accessDenied/**", "/vaadinServlet/**").permitAll() 
         .antMatchers("/authorized", "/**").fullyAuthenticated(); 
      } 

      @Bean 
      public DaoAuthenticationProvider createDaoAuthenticationProvider() { 
       DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); 

       provider.setUserDetailsService(userDetailsService); 
       provider.setPasswordEncoder(passwordEncoder()); 
       return provider; 
      } 

      @Bean 
      public BCryptPasswordEncoder passwordEncoder() { 
       return new BCryptPasswordEncoder(); 
      } 

あなたはcrsfを無効にする必要がなく、vaadinは独自のcrsf保護を持っているので、それは問題ありません。

は、さらにあなたがそのリソースにアクセスすることができますので、vaadinいくつかのURIを許可する必要があります。/VAADIN/**は絶対に必要ですが、私はまた/vaadinServlet/**/PUSH/**/HEARTBEAT/**を許可するreccommendだろうが、それはあなたが使用Vaadinのどの部分に依存します。

第二に、私のUserDetailsService

@Service("authService") 
public class AuthService implements UserDetailsService { 

     @Autowired 
     CustomUserRepository userRepository; 

     @Override 
     public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { 
      CustomUser user = userRepository.findCustomUserByUserName(userName); 

      return user; 
     } 

} 

DaoAuthenticationProviderUserDetailsインタフェースを実装するクラスのオブジェクトを取得するためのUserDetails "loadUserByUserName方法を使用しています。 UserDetailsInterfaceに記載されているすべての属性はnullであってはならないことに注意してください。それ以外の場合は、DaoAuthenticationProviderによって後でNullPointerExceptionが投じられます。

私はUserDetailsインタフェースを実装するJPAエンティティを作成しました:

@Entity 
public class CustomUser implements UserDetails { 

     @Id 
     @GeneratedValue(strategy = GenerationType.IDENTITY) 
     Long id; 
     @ManyToMany(fetch = FetchType.EAGER) 
     Collection<Authorities> authorities; 
     String password; 
     String userName; 
     Boolean accountNonExpired; 
     Boolean accountNonLocked; 
     Boolean credentialsNonExpired; 
     Boolean enabled; 

     @Autowired 
     @Transient 
     BCryptPasswordEncoder passwordEncoder; 

     @Override 
     public Collection<? extends GrantedAuthority> getAuthorities() { 
      return authorities; 
     } 

     @Override 
     public String getPassword() { 
      return password; 
     } 

     @Override 
     public String getUsername() { 
      return userName; 
     } 

     @Override 
     public boolean isAccountNonExpired() { 
      return accountNonExpired; 
     } 

     @Override 
     public boolean isAccountNonLocked() { 
      return accountNonLocked; 
     } 

     @Override 
     public boolean isCredentialsNonExpired() { 
      return credentialsNonExpired; 
     } 

     @Override 
     public boolean isEnabled() { 
      return enabled; 
     } 

     public void setId(Long id) { 
      this.id = id; 
     } 

     public void setAuthorities(Collection<Authorities> authorities) { 
      this.authorities = authorities; 
     } 

     public void setPassword(String password) { 
      this.password = passwordEncoder.encode(password); 
     } 

     public void setUserName(String userName) { 
      this.userName = userName; 
     } 

     public void setAccountNonExpired(Boolean accountNonExpired) { 
      this.accountNonExpired = accountNonExpired; 
     } 

     public void setAccountNonLocked(Boolean accountNonLocked) { 
      this.accountNonLocked = accountNonLocked; 
     } 

     public void setCredentialsNonExpired(Boolean credentialsNonExpired) { 
      this.credentialsNonExpired = credentialsNonExpired; 
     } 

     public void setEnabled(Boolean enabled) { 
      this.enabled = enabled; 
     } 

    } 

当局エンティティプラス:

@Entity 
public class Authorities implements GrantedAuthority { 

     @Id 
     @GeneratedValue(strategy = GenerationType.IDENTITY) 
     Long id; 

     String authority; 

     @Override 
     public String getAuthority() { 
      return authority; 
     } 

     public void setAuthority(String authority) { 
      this.authority = authority; 
     } 

} 

明らかにあなたが最初の前に、データベース内の一部のユーザーデータを保存する必要があります認証が機能します。

Vaadinでは、異なるビューを持つ1つのUIを使用して作業することができませんでした。そのため、ログイン用に2つのUIを使用し、メインアプリケーション用に2つのUIを使用しました。私はクラスの注釈にURIのパスを設定することができVaadinで

@SpringUI(path = "/login") 
@Title("LoginPage") 
@Theme("valo") 
public class LoginUI extends UI { 
    //... 
} 

この構成では、私のログイン画面がlocalhost:port/loginlocalhost:port/mainで私のメインのアプリケーションで使用可能です。

私は私のloginUIでbutton.clickメソッド内でプログラムでユーザーログイン:

Authentication auth = new UsernamePasswordAuthenticationToken(userName.getValue(),password.getValue()); 
Authentication authenticated = daoAuthenticationProvider.authenticate(auth); 
      SecurityContextHolder.getContext().setAuthentication(authenticated); 

//redirect to main application 
getPage().setLocation("/main"); 

私はそれはあなたのいくつかを助け願っています。

+0

パブリックリポジトリ内の設定全体を参照として使用しますか? –

関連する問題