Hola, estaba haciendo una aplicación sencilla con login y mi problema es que al iniciar sesión en el main y hacer click en algún botón para cambiar de vista me solicita volver a logearme y no se como guardar la sesión activa, si alguien pudiera ayudarme se lo agradecería muchísimo. Les dejo aca todo el código de mi aplicación
package com.diego.vaadin1.moodle;
import java.util.ArrayList;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class User implements UserDetails{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "username")
private String username;
@Column(name = "password")
private String password;
public Collection<? extends GrantedAuthority> getAuthorities() {
return new ArrayList<GrantedAuthority>();
}
public String getPassword() {
return this.password;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return this.username;
}
public boolean isAccountNonExpired() {
return true;
}
public boolean isAccountNonLocked() {
return true;
}
public boolean isCredentialsNonExpired() {
return true;
}
public boolean isEnabled() {
return true;
}
}
package com.diego.vaadin1;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import com.vaadin.flow.component.page.AppShellConfigurator;
import com.vaadin.flow.theme.Theme;
import com.vaadin.flow.theme.lumo.Lumo;
@SpringBootApplication
@Theme(themeClass = Lumo.class)
public class Vaadin1Application implements AppShellConfigurator {
public static void main(String[] args) {
SpringApplication.run(Vaadin1Application.class, args);
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
package com.diego.vaadin1.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import com.diego.vaadin1.views.LoginView;
import com.vaadin.flow.spring.security.VaadinWebSecurity;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends VaadinWebSecurity {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private BCryptPasswordEncoder encoder;
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
setLoginView(http, LoginView.class);
}
@Override
protected void configure(WebSecurity web) throws Exception {
web.ignoring().requestMatchers("/images/**", "/login", "/signup");
super.configure(web);
}
@Bean
public AuthenticationManager authManager(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
authenticationManagerBuilder.authenticationProvider(authenticationProvider());
return authenticationManagerBuilder.build();
}
@Bean
public DaoAuthenticationProvider authenticationProvider(){
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(encoder);
return provider;
}
}
package com.diego.vaadin1.moodle.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import com.diego.vaadin1.moodle.User;
@Repository
public interface SecurityRepository extends JpaRepository<User, Integer>{
@Query("select u from User u where u.username=:username")
User findByUsername( @Param("username") String username);
}
package com.diego.vaadin1.services;
public interface SecurityService {
public void save(String username, String password);
public void logout();
}
package com.diego.vaadin1.services;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Service;
import com.diego.vaadin1.moodle.User;
import com.diego.vaadin1.moodle.repository.SecurityRepository;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.server.VaadinServletRequest;
@Service
public class SecurityServiceImpl implements SecurityService,
UserDetailsService{
@Autowired
private SecurityRepository securityR;
@Autowired
public BCryptPasswordEncoder encoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = securityR.findByUsername(username);
return user;
}
@Override
public void save(String username, String password) {
User user = new User();
user.setUsername(username);
user.setPassword(encoder.encode(password));
securityR.save(user);
}
@Override
public void logout() {
UI.getCurrent().getPage().setLocation("/login");
var logoutHandler = new SecurityContextLogoutHandler();
logoutHandler.logout(VaadinServletRequest.getCurrent()
.getHttpServletRequest(), null, null);
}
}
package com.diego.vaadin1.views;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.auth.AnonymousAllowed;
@PageTitle("Login")
@Route(value = LoginView.PATH)
//se accede sin necesidad de auntentificacion
@AnonymousAllowed
public class LoginView extends VerticalLayout{
private static final String PATH = "/login";
public LoginView(LoginViewFactory loginFactory) {
add(loginFactory.create());
}
}
package com.diego.vaadin1.views;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.html.Image;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.notification.Notification.Position;
import com.vaadin.flow.component.notification.NotificationVariant;
import com.vaadin.flow.component.orderedlayout.FlexComponent.Alignment;
import com.vaadin.flow.component.orderedlayout.FlexComponent.JustifyContentMode;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.PasswordField;
import com.vaadin.flow.component.textfield.TextField;
@org.springframework.stereotype.Component
public class LoginViewFactory {
@Autowired
private DaoAuthenticationProvider authenticationProvider;
private class LoginForm{
private VerticalLayout root;
private TextField username;
private PasswordField password;
private Button login;
private Button signup;
public LoginForm init() {
username = new TextField("Username");
password = new PasswordField("Password");
login = new Button("Login");
signup = new Button("Signup");
login.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
signup.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
root = new VerticalLayout();
root.setAlignItems(Alignment.CENTER);
root.setJustifyContentMode(JustifyContentMode.CENTER);
root.setMargin(true);
return this;
}
private void login() {
try {
var auth = new UsernamePasswordAuthenticationToken(username.getValue(), password.getValue());
var authenticated = authenticationProvider.authenticate(auth);
SecurityContextHolder.getContext().setAuthentication(authenticated);
login.getUI().ifPresent(ui -> ui.navigate(""));
}catch (AuthenticationException e) {
Notification notification = Notification.
show("Incorrect username or password...");
notification.addThemeVariants(NotificationVariant.LUMO_ERROR);
notification.setPosition(Position.TOP_CENTER);
e.printStackTrace();
}
}
public Component layout() {
//root.add(new Image(Constants.LOGIN_URL, "Login Image"));
root.add(username);
root.add(password);
root.add(new HorizontalLayout(login, signup));
login.addClickListener(e -> login());
//signup.addClickListener(e -> signup());
return root;
}
}
public Component create() {
return new LoginForm().init().layout();
}
}
package com.diego.vaadin1.views;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import com.diego.vaadin1.moodle.Status;
import com.diego.vaadin1.moodle.Student;
import com.diego.vaadin1.services.SecurityService;
import com.diego.vaadin1.services.StudentService;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.value.ValueChangeMode;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.theme.lumo.Lumo;
import jakarta.annotation.security.PermitAll;
@Route(value = "")
@PageTitle(value = "Home")
@PermitAll
public class MainView extends VerticalLayout {
// constructor injection
private final StudentService studentS;
private final SecurityService securityService;
private Grid<Student> grid;
private LogoLayout logoLayout;
private TextField filterField;
private Checkbox themeToggle;
private static boolean isChecked;
public MainView(StudentService studentS, SecurityService securityService) {
this.studentS = studentS;
this.securityService = securityService;
setSizeFull();
setAlignItems(Alignment.CENTER);
createFieldsVariables();
configurateGrid();
add(logoLayout, createToolbar(), grid);
loadStudents();
}
private Checkbox createToogle() {
// TODO Auto-generated method stub
this.themeToggle = new Checkbox("Dark Box");
this.themeToggle.setValue(isChecked );
this.themeToggle.addValueChangeListener(e->{
MainView.isChecked =!isChecked;
setTheme(isChecked);
});
return this.themeToggle;
}
private void setTheme(boolean dark) {
// TODO Auto-generated method stub
var js = MessageFormat.format("""
document.documentElement.setAttribute("theme", "{0}")
""", dark ? Lumo.DARK : Lumo.LIGHT);
//execute java script
getElement().executeJs(js);
}
private Component createToolbar() {
// TODO Auto-generated method stub
filterField.setPlaceholder("Filter by name...");
filterField.setClearButtonVisible(true);
filterField.setValueChangeMode(ValueChangeMode.LAZY);
filterField.addValueChangeListener(e -> updateStudents());
Button addStudentButton = new Button("Add Student");
addStudentButton.addClickListener(e -> getUI().ifPresent(ui -> ui.navigate("add-student")));
Button deleteStudentButton = new Button("Delete Student");
deleteStudentButton.addClickListener(e -> getUI().ifPresent(ui -> ui.navigate("delete-student")));
Button logout = new Button("Logout");
logout.addClickListener(e->securityService.logout());
return new HorizontalLayout(filterField, addStudentButton, deleteStudentButton
,logout,createToogle());
}
private void updateStudents() {
// TODO Auto-generated method stub
grid.setItems(studentS.find(filterField.getValue()));
}
private void configurateGrid() {
// TODO Auto-generated method stub
grid.setSizeFull();
grid.setColumns("country", "zipcode");
grid.addColumn(s -> s.getName()).setHeader("Name");
grid.addColumn(s -> s.getAge()).setHeader("Age");
grid.getColumns().forEach(col -> col.setAutoWidth(true));
grid.addComponentColumn(s -> {
Icon icon;
if (s.getStatus().getName().equals("ACTIVE")) {
icon = VaadinIcon.CIRCLE.create();
icon.setColor("green");
} else if (s.getStatus().getName().equals("PASSIVE")) {
icon = VaadinIcon.CLOSE_CIRCLE.create();
icon.setColor("red");
} else {
icon = VaadinIcon.CHECK_CIRCLE.create();
icon.setColor("orange");
}
return icon;
}).setHeader("Status");
}
private void loadStudents() {
grid.setItems(studentS.findAll());
}
private void createFieldsVariables() {
// TODO Auto-generated method stub
this.logoLayout = new LogoLayout();
this.grid = new Grid<>(Student.class);
this.filterField = new TextField();
}
}
package com.diego.vaadin1.views;
import java.util.List;
import com.diego.vaadin1.moodle.Status;
import com.diego.vaadin1.moodle.Student;
import com.diego.vaadin1.services.StatusService;
import com.diego.vaadin1.services.StudentService;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.HasValue;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.notification.Notification.Position;
import com.vaadin.flow.component.notification.NotificationVariant;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.binder.BeanValidationBinder;
import com.vaadin.flow.data.binder.Binder;
import com.vaadin.flow.data.binder.ValidationException;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import jakarta.annotation.security.PermitAll;
@PageTitle("Add Students")
@Route(value = "add-student")
@PermitAll
public class AddStudentView extends VerticalLayout {
private TextField age;
private TextField name;
private TextField country;
private TextField zipcode;
private ComboBox<Status> status;
private LogoLayout image;
private Button save;
private Button close;
private final StatusService statusS;
private final StudentService studentS;
private Student student;
private Binder<Student> binder;
public AddStudentView(StatusService statusS, StudentService studentS) {
this.statusS = statusS;
this.studentS = studentS;
setAlignItems(Alignment.CENTER);
createVariables();
createStatus();
createBinder();
add(image);
add(createFormLayout());
}
private void createBinder() {
// TODO Auto-generated method stub
this.student = new Student();
binder = new BeanValidationBinder<>(Student.class);
binder.bindInstanceFields(this);
}
private void createStatus() {
// TODO Auto-generated method stub
List<Status>statusItems = statusS.findAll();
status.setItems(statusItems);
status.setValue(statusItems.get(0));
status.setItemLabelGenerator(Status::getName);
}
private Component createFormLayout() {
// TODO Auto-generated method stub
FormLayout formLayout = new FormLayout();
formLayout.add(this.name, this.age, this.country, this.zipcode, this.status, createButton());
formLayout.setColspan(image, 2);
formLayout.setColspan(name, 2);
return formLayout;
}
private Component createButton() {
// TODO Auto-generated method stub
save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
close.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
close.addClickListener(e -> closeView());
save.addClickListener(e -> saveStudent());
return new HorizontalLayout(save, close);
}
private void saveStudent() {
// TODO Auto-generated method stub
try {
binder.writeBean(student);
studentS.save(student);
clearFields();
Notification notification = Notification.show("Student save succefully");
notification.addThemeVariants(NotificationVariant.LUMO_SUCCESS);
notification.setPosition(Position.TOP_CENTER);
} catch (ValidationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void clearFields() {
// TODO Auto-generated method stub
student = new Student();
status.setValue(statusS.findAll().get(0));
binder.getFields().forEach(HasValue::clear);
}
private void closeView() {
// TODO Auto-generated method stub
getUI().ifPresent(ui -> ui.navigate(""));
}
private void createVariables() {
this.age = new TextField("Age");
this.name = new TextField("Name");
this.country = new TextField("Country");
this.zipcode = new TextField("Zipcode");
this.status = new ComboBox<Status>("Status");
this.image = new LogoLayout();
this.save = new Button("Save");
this.close = new Button("Close");
}
}