This is my : login.tsx
import { ViewConfig } from '@vaadin/hilla-file-router/types.js';
import { useSignal } from '@vaadin/hilla-react-signals';
import { LoginI18n, LoginOverlay, LoginOverlayElement } from '@vaadin/react-components/LoginOverlay.js';
import { useAuth } from 'Frontend/util/auth.js';
export const config: ViewConfig = {
menu: { exclude: true },
};
const loginI18n: LoginI18n = {
...new LoginOverlayElement().i18n,
header: { title: 'RiconTrans Login', description: '' },
};
export default function LoginView() {
const { login } = useAuth();
const loginError = useSignal(false);
return (
<LoginOverlay
opened
error={loginError.value}
noForgotPassword
i18n={loginI18n}
onLogin={async ({ detail: { username, password } }) => {
const { defaultUrl, error, redirectUrl } = await login(username, password);
if (error) {
loginError.value = true;
} else {
const url = redirectUrl ?? defaultUrl ?? '/Main'; // Ensure the path starts with '/'
const path = new URL(url, document.baseURI).pathname;
document.location.href = path;
}
}}
/>
);
}
);
}
serving as the view of logging in, and here is my security package:
AuthenticatedUser
:
package com.ricontrans.application.security;
import com.ricontrans.application.data.User;
import com.ricontrans.application.data.UserRepository;
import com.ricontrans.application.services.UserService;
import com.vaadin.flow.spring.security.AuthenticationContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
@Component
public class AuthenticatedUser {
private static final Logger logger = LoggerFactory.getLogger(AuthenticatedUser.class);
private final UserService userService;
private final AuthenticationContext authenticationContext;
public AuthenticatedUser(AuthenticationContext authenticationContext, UserService userService) {
this.userService = userService;
this.authenticationContext = authenticationContext;
}
@Transactional
public Optional<Object> get() {
logger.info("Attempting to get authenticated user.");
Optional<Object> user = authenticationContext.getAuthenticatedUser(UserDetails.class)
.map(userDetails -> {
logger.info("Authenticated user found: {}", userDetails.getUsername());
// Call your custom findByUsername method from UserService
Optional<User> foundUser = UserService.findByUsername(userDetails.getUsername());
if (foundUser.isPresent()) {
return (Object) foundUser.get(); // Cast User to Object
} else {
return Optional.empty();
}
});
user.ifPresentOrElse(
u -> logger.info("User retrieved from repository: {}", u),
() -> logger.warn("No user found in repository.")
);
return user;
}
public Optional<UserDetails> getCurrentUserDetails() {
logger.info("Attempting to get current user details from security context.");
org.springframework.security.core.Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getPrincipal() instanceof UserDetails) {
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
logger.info("Current user details found: {}", userDetails.getUsername());
return Optional.of(userDetails);
}
logger.info("No user details found in security context.");
return Optional.empty();
}
public void logout() {
logger.info("Logging out user.");
authenticationContext.logout();
}
}
SecurityConfiguration
:
package com.ricontrans.application.security;
import com.vaadin.flow.spring.security.VaadinWebSecurity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@EnableWebSecurity
@Configuration
public class SecurityConfiguration extends VaadinWebSecurity {
private static final Logger logger = LoggerFactory.getLogger(SecurityConfiguration.class);
private static final String LOGIN_FAILURE_URL = "/login?error";
private static final String SUCCESS_URL = "/Main";
private static final String LOGIN_URL = "/login";
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
logger.debug("Configuring HTTP security.");
http.authorizeHttpRequests(authorize -> {
logger.debug("Permitting all requests to /images/*.png");
authorize.requestMatchers(new AntPathRequestMatcher("/images/*.png")).permitAll();
});
// Icons from the line-awesome addon
http.authorizeHttpRequests(authorize -> {
logger.debug("Permitting all requests to /line-awesome/**/*.svg");
authorize.requestMatchers(new AntPathRequestMatcher("/line-awesome/**/*.svg")).permitAll();
});
// Set custom success and failure handlers
http.formLogin()
.loginPage(LOGIN_URL)
.successForwardUrl(SUCCESS_URL)
.failureUrl(LOGIN_FAILURE_URL)
.permitAll();
super.configure(http);
logger.debug("Setting login view to /login");
setLoginView(http, LOGIN_URL);
}
}
// Set custom success and failure handlers
http.formLogin()
.loginPage(LOGIN_URL)
.successForwardUrl(SUCCESS_URL)
.failureUrl(LOGIN_FAILURE_URL)
.permitAll();
super.configure(http);
logger.debug("Setting login view to /login");
setLoginView(http, LOGIN_URL);
}
UserDetailsServiceImpl
package com.ricontrans.application.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ricontrans.application.data.User;
import com.ricontrans.application.data.UserRepository;
import com.ricontrans.application.services.UserService;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import com.ricontrans.application.data.Role;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
private static final Logger logger = LoggerFactory.getLogger(UserDetailsServiceImpl.class);
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
@Autowired
public UserDetailsServiceImpl(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
@Override
@Transactional
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
logger.info("Attempting to load user by username: {}", username);
try {
User user = UserService.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("No user present with username: " + username));
logger.info("User found: {}", username);
Set<Role> roles = UserService.findRolesByUserId(user.getId());
List<GrantedAuthority> authorities = roles.stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role.getRoleName()))
.collect(Collectors.toList());
logger.info("Assigning roles to user: {}", authorities);
logger.info("user.getUsername(): {}", user.getUsername());
logger.info("user.getHashedPassword()", user.getHashedPassword());
return new org.springframework.security.core.userdetails.User(user.getUsername(),
user.getHashedPassword(), authorities);
} catch (Exception e) {
logger.error("Error loading user by username: {}. Exception: {}", username, e.getMessage(), e);
throw e;
}
}
private static List<GrantedAuthority> getAuthorities(User user) {
return user.getRoles().stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role))
.collect(Collectors.toList());
}
}
I also have a user service file for my database queyring .From the logging of my user named "qq"
2024-07-08 14:11:52 INFO c.r.a.security.AuthenticatedUser - Authenticated user found: qq
2024-07-08 14:11:52 INFO c.r.application.services.UserService - Attempting to find user by username: qq
2024-07-08 14:11:52 INFO c.r.application.services.UserService - User found by username 'qq': com.ricontrans.application.data.User@11
2024-07-08 14:11:52 INFO c.r.a.security.AuthenticatedUser - User retrieved from repository: com.ricontrans.application.data.User@11
2024-07-08 14:11:52 INFO c.r.a.security.AuthenticatedUser - Attempting to get authenticated user.
2024-07-08 14:11:52 INFO c.r.a.security.AuthenticatedUser - Authenticated user found: qq
2024-07-08 14:11:52 INFO c.r.application.services.UserService - Attempting to find user by username: qq
2024-07-08 14:11:52 INFO c.r.application.services.UserService - User found by username 'qq': com.ricontrans.application.data.User@11
2024-07-08 14:11:52 INFO c.r.a.security.AuthenticatedUser - User retrieved from repository: com.ricontrans.application.data.User@11
everything seems correct but the problem is :
That the redirection to /Main
never happens, it just redirects to the root route, where all the user is authenticated because he can visit all the views needing permission. Also everything i tried to show a notification after a successful login never happens.
2
Answers
Unfortunately,nothing changed!
Try using
defaultSuccessUrl
instead ofsuccessForwardUrl
in yourSecurityConfiguration
class.