簡體   English   中英

使用Vaadin登錄的Spring Boot安全性

[英]Spring Boot Security with Vaadin Login

我嘗試構建一個基於Spring Boot(1.2.7.RELEASE)和Vaadin(7.6.3)的應用程序。 我的問題是我無法將Spring Security與Vaadin集成。 我想要一個自定義的Vaadin內置的LoginScreen和Spring Security控件。 我的項目設置如下:

@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登錄界面

 @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
        }

    }

當我啟動我的應用程序時,spring會將我重定向到我的登錄UI,這很好。

但我不知道如何根據spring安全機制對用戶進行身份驗證並調度到我的mainUI。

我也面臨着csrf令牌的問題,如果我不禁用csrf我會得到crfs令牌是null異常。 我找到了很多處理這些問題的例子,但Vaadin沒有提供解決方案。

感謝幫助。

經過一周的奮斗和研究,我得以實現這一目標。 這是非常令人疲憊的,因為互聯網上有很多信息和解決方案,大多數都使用基於xml的配置或基於JSP表單的登錄,直到現在我找不到另一個沒有xml配置文件的解決方案,使用Vaadin框架創建一個自定義登錄頁面。

我無法保證這是最佳做法或最簡單的解決方案。 此外我沒有評估它的每一部分,登錄機制盡我所能,但也許可能存在一些我尚未發現的問題。

也許它會幫助那些面臨同樣問題的人,所以我會在這里發布我的答案。

首先我的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保護。

此外,您需要允許一些URI,以便vaadin可以訪問其資源: /VAADIN/**是絕對必要的,我還建議允許/vaadinServlet/**/PUSH/**/HEARTBEAT/** ,但它取決於你使用的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;
        }

}

DaoAuthenticationProvider使用UserDetailsloadUserByUserName方法來獲取實現UserDetails接口的類的對象。 請注意, 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中,我無法通過使用一個具有不同視圖的UI來實現它,因此我最終使用兩個UI用於登錄,另一個用於主應用程序。

在Vaadin中,我可以在類注釋中設置URI路徑:

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

使用此配置,我的登錄屏幕可在localhost:port/login和我的主應用程序在localhost: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");

我希望它能幫助你們中的一些人。

作為給定方法的替代方案,您還可以依賴vaadin4spring ,這是一種“非官方”擴展,可進一步集成Vaadin和Spring

它目前提供了兩種集成Spring Security的方法,它們似乎工作正常(即使它們不適合您,代碼示例應該為您提供足夠的見解來編寫自定義集成代碼)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM