bc_tom
bc_tom

Reputation: 41

Vaadin Custom Login Form

my colleagues and I have created a UI with Vaadin23 and it also contains the default Vaadin Login Form from the Tutorial/ Vaadin Starter Application:

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);
  }
  // ...
}

Since we require a different way of logging in, we need to use a custom login form. The problem is, that we cannot edit the Vaadin standard login form but we'd like to keep the security mechanism for now. We also understand the basic process of the login mechanism. Filling out the form which starts the firing of a LoginEvent within the AbstractLogin class.

Our login form should contain a Select field containing the users, a password field that only uses a NumPad to enter a pin code and a Login Button to submit the form. How do we have to configure a custom login form in order to connect to the security functionality?

Possible Vaadin LoginForm in Typescript (The styling attributes come from copy&pasting and can be ignored). Help for implementing the TypeScript component as well as the connected Java View class is greatly appreciated.

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

I can also provide additional information if needed.

This is the code of the Vaadin Tutorial.

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();
  }

}

SecurityConfiguration.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));
    }

}

Upvotes: 0

Views: 1221

Answers (1)

Tatu Lund
Tatu Lund

Reputation: 10643

public class LoginView extends LoginOverlay

Vaadin does not mandate that you need to extend LoginOverlay or LoginForm in your LoginView. These two components are basic implementations for such view, which can be used to reduce boiler plate when applicable. They are not meant to be applicable in 100% of the cases, but the common ones. You can compose your LoginView anyway you want using more elementary components and you can define it with template using TypeScript or fully compose the view with 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);
    }
}

Upvotes: 0

Related Questions