我和我的同事使用 Vaadin23 创建了一个 UI,它还包含教程/ Vaadin 入门应用程序中的默认 Vaadin 登录表单:
public class LoginView extends LoginOverlay implements BeforeEnterObserver {
private final AuthenticatedUser authenticatedUser;
public LoginView(AuthenticatedUser authenticatedUser) {
this.authenticatedUser = authenticatedUser;
setAction(RouteUtil.getRoutePath(VaadinService.getCurrent().getContext(), getClass()));
LoginI18n i18n = LoginI18n.createDefault();
i18n.setHeader(new LoginI18n.Header());
i18n.setAdditionalInformation(null);
setI18n(i18n);
setForgotPasswordButtonVisible(false);
setOpened(true);
}
// ...
}
由于我们需要不同的登录方式,因此我们需要使用自定义登录表单。 问题是,我们无法编辑 Vaadin 标准登录表单,但我们现在想保留安全机制。我们也了解了登录机制的基本流程。填写表单以开始在 AbstractLogin 类中触发 LoginEvent。
我们的登录表单应包含一个包含用户的 Select 字段、一个仅使用数字键盘输入 PIN 码的密码字段和一个用于提交表单的登录按钮。 我们如何配置自定义登录表单才能连接到安全功能?
Typescript 中可能的 Vaadin LoginForm (样式属性来自复制和粘贴,可以忽略)。非常感谢您帮助实现 TypeScript 组件以及连接的 Java View 类。
<vaadin-vertical-layout style="width: 100%; height: 100%;" class="content">
<vaadin-vertical-layout theme="spacing" style="width: 100%; height: 100%;">
<vaadin-form-layout id="login-form">
<vaadin-select label="User" id="username-select"></vaadin-select>
<vaadin-password-field label="Password" id="password-field"></vaadin-password-field>
<vaadin-button theme="primary error" tabindex="0" id="login-button">
Login
</vaadin-button>
</vaadin-form-layout>
</vaadin-vertical-layout>
</vaadin-vertical-layout>
如果需要,我还可以提供其他信息。
这是 Vaadin 教程的代码。
AuthenticatedUser.class
@Component
public class AuthenticatedUser {
private final UserRepository userRepository;
private final AuthenticationContext authenticationContext;
public AuthenticatedUser(AuthenticationContext authenticationContext, UserRepository userRepository) {
this.userRepository = userRepository;
this.authenticationContext = authenticationContext;
}
public Optional<User> get() {
return authenticationContext.getAuthenticatedUser(UserDetails.class)
.map(userDetails -> userRepository.findByUsername(userDetails.getUsername()));
}
public void logout() {
authenticationContext.logout();
}
}
安全配置.class
@EnableWebSecurity
@Configuration
public class SecurityConfiguration extends VaadinWebSecurity {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().requestMatchers(new AntPathRequestMatcher("/images/*.png")).permitAll();
super.configure(http);
setLoginView(http, LoginView.class);
}
}
UserDetailsServiceImpl.class
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserRepository userRepository;
public UserDetailsServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
private static List<GrantedAuthority> getAuthorities(User user) {
return user.getRoles().stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role))
.collect(Collectors.toList());
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("No user present with username: " + username);
}
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getHashedPassword(),
getAuthorities(user));
}
}
公共类LoginView扩展LoginOverlay
Vaadin 不要求您需要在 LoginView 中扩展
LoginOverlay
或 LoginForm
。这两个组件是此类视图的基本实现,在适用时可用于减少样板代码。它们并不是适用于 100% 的情况,而是适用于常见情况。您可以使用更多基本组件以任何方式组合您的 LoginView,并且可以使用 TypeScript 通过模板定义它,或者使用 Java 完全组合视图。
@Tag("form")
public class MyLoginForm extends HtmlContainer {
public MyLoginForm() {
VaadinIcon.KEY.create();
addClassNames(LumoUtility.Display.FLEX,
LumoUtility.FlexDirection.COLUMN, LumoUtility.AlignItems.START);
TextField user = new TextField("Username");
PasswordField pass = new PasswordField("Password");
Button login = new Button("Login");
login.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
login.getElement().setAttribute("on-click", "submit");
getElement().setAttribute("method", "POST");
getElement().setAttribute("action", "login");
add(user, pass, login);
}
}