Reputation: 1
I have created a field for user login, user data is taken from MySQL database. I am taken to a new window named /grid. In /grid, I have a "Save" button, which I want to use to save some data to the MySQL database. However, the problem is that when I press the "Save" button, I lose the logged-in user, and the method called by the button shows the user as "anonymous".
In the Vaadin session, I can see which user is logged in, but Spring loses it. Can anyone help me? Advise me on what I might be missing in my configuration? Perhaps there is a multithreading problem, but how can I deal with it effectively?
Here are the console logs:
User successful logged in: fish1
Logged user: fish1
Username while button is pressing in /grid: fish1
User in SecurityContext in class EnterProductService: anonymousUser
User in VaadinSession in class EnterProductService: fish1
@Service public class EnterProductService {
@Autowired
private RestTemplate restTemplate;
public String urlForMapping = null;
public boolean enteredProductError = false;
public boolean reqOpenFoodFacts = false;
public boolean reqFoodDataCentral = false;
public String reqBarcode = null;
public MealType reqMealType = null;
public double reqGrams = 0;
private final Executor executor;
@Autowired
public EnterProductService(@Qualifier("taskExecutor") Executor executor) {
this.executor = new DelegatingSecurityContextExecutor(executor);
}
@PreAuthorize("hasRole('USER')")
@Transactional
public void onSaveButtonClicked(String searchProductField, String gramAmount, MealType mealType) {
SecurityContext securityContext = SecurityContextHolder.getContext();
VaadinSession currentSession = VaadinSession.getCurrent();
UI currentUI = UI.getCurrent();
executor.execute(() -> {
VaadinSession.setCurrent(currentSession);
try {
currentSession.lock();
currentUI.access(() -> {
SecurityContextHolder.setContext(securityContext);
System.out.println("User in SecurityContext in class EnterProductService: " + SecurityContextHolder.getContext().getAuthentication().getName());
System.out.println("User in VaadinSession in class EnterProductService: " + VaadinSession.getCurrent().getSession().getAttribute("username"));
if (searchProductField != null && mealType != null && gramAmount != null) {
if (isOnlyNumeric(searchProductField)) {
reqBarcode = searchProductField;
reqGrams = Double.parseDouble(gramAmount);
reqMealType = mealType;
urlForMapping = String.format("/openfoodfacts/%s/%s/%s", searchProductField, gramAmount, mealType.name());
reqOpenFoodFacts = true;
reqFoodDataCentral = false;
} else if (isOnlyLetters(searchProductField)) {
reqBarcode = searchProductField;
reqGrams = Double.parseDouble(gramAmount);
reqMealType = mealType;
urlForMapping = String.format("/fooddatacentral/%s/%s/%s", searchProductField, gramAmount, mealType.name());
reqFoodDataCentral = true;
reqOpenFoodFacts = false;
} else {
enteredProductError = true;
reqOpenFoodFacts = false;
reqFoodDataCentral = false;
}
}
});
} finally {
currentSession.unlock();
}
});
}
public void sendRequestToApi() {
String url = urlForMapping;
String response = restTemplate.getForObject("http://localhost:8080/product" + url, String.class);
}
public boolean isOnlyNumeric (String string){
return string.matches("\\d+");
}
public boolean isOnlyLetters (String string){
return string.matches("[a-zA-Z]+");
}
}
Here is my class where the user in SecurityContext is missing:
Here I call onSaveButtonClicked() and the user is still available:
saveButton.addClickListener(event -> {
System.out.println("Username while button is pressing in /grid " + username);
enterProductService.onSaveButtonClicked(
searchProductField.getValue(),
gramAmount.getValue(),
comboBox.getValue());
enterProductService.sendRequestToApi();
I attempted to handle multithreading by checking active sessions, but this doesn't seem to work.
What am I missing in my configuration? Why is my user being lost in SecurityContext but still available in the VaadinSession?
@Configuration
@EnableWebSecurity
public class SecurityConfig extends VaadinWebSecurity {
private final UserService userService;
@Autowired
public SecurityConfig(@Lazy UserService userService) {
this.userService = userService;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/login", "/user", "/VAADIN/**", "/UIDL/**", "/HEARTBEAT/**", "/resources/**", "/websocket-client.js").permitAll()
.requestMatchers("/grid").hasRole("USER")
.anyRequest().permitAll()
)
.formLogin(form -> form
.loginPage("/login")
.defaultSuccessUrl("/grid", true)
.permitAll()
)
.logout(logout -> logout
// .logoutUrl("/logout")
.logoutSuccessUrl("/login")
.permitAll()
)
.csrf(csrf -> csrf.disable());
return http.build();
}
@Bean
public AuthenticationManager authenticationManager(PasswordEncoder passwordEncoder) {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userService);
authenticationProvider.setPasswordEncoder(passwordEncoder);
return new ProviderManager(authenticationProvider);
}
Upvotes: 0
Views: 101
Reputation: 1266
The problem is in the expression
.anyRequest().permitAll()
This code disables secured access to all your endpoints.
If you replace it with
.anyRequest().authenticated()
then Spring Security authorization will work.
Upvotes: -1