![](/img/trans.png)
[英]Vaadin 8 (withouth Spring Boot/Security) and Keycloak not working
[英]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
使用UserDetails
的loadUserByUserName
方法來獲取實現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.