Hi, I am making a vaadin v24, java 21, spring boot 3 app and need some help implementing login and logout. I have it implemented with local account and using google. What I am having trouble with is that I want when I log out for vaadin to use an annonymous account how do I do that? Bellow is some relevant code.
package com.web.photo.app.security.config;
@EnableWebSecurity
@Configuration
@Slf4j
@AllArgsConstructor
public class SecurityConfiguration extends VaadinWebSecurity {
private static final String LOGIN_URL = "/login";
private static final String FEED_URL = "/feed";
private static final String REGISTER_GOOGLE_URL = "/register/google";
private ServletContext servletContext;
private AppUserService appUserService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth ->
{
auth.requestMatchers(HttpMethod.GET, "/images/*.png").permitAll();
auth.requestMatchers(AntPathRequestMatcher.antMatcher("/login*")).permitAll();
auth.requestMatchers(AntPathRequestMatcher.antMatcher("/h2-console")).permitAll();
});
http.oauth2Login(config -> config.loginPage(LOGIN_URL).permitAll()
.successHandler((request, response, authentication) -> oauthLoginSuccessHandler(response, authentication)))
.formLogin(config -> config.loginPage(LOGIN_URL).permitAll());
http.headers(configurer -> configurer.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable));
super.configure(http);
setLoginView(http, LoginView.class);
}
private void oauthLoginSuccessHandler(HttpServletResponse response, Authentication authentication) throws IOException {
log.info("Google login success handler called");
DefaultOidcUser userLogged = (DefaultOidcUser) authentication.getPrincipal();
AppUser userInfo;
if (appUserService.userExists(userLogged.getAttribute("email"))) {
userInfo = appUserService.getUserByEmail(userLogged.getAttribute("email"));
AuthUtil.setSecurityContext(userInfo);
response.sendRedirect(servletContext.getContextPath() + FEED_URL);
log.debug("Loaded existing user");
} else {
userInfo = AppUser
.builder()
.firstName(userLogged.getAttribute("given_name"))
.lastName(userLogged.getAttribute("family_name"))
.email(userLogged.getAttribute("email"))
.role(USER)
.accountType(GOOGLE)
.isRegistered(false)
.build();
appUserService.saveUser(userInfo);
AuthUtil.setSecurityContext(userInfo);
response.sendRedirect(servletContext.getContextPath() + REGISTER_GOOGLE_URL);
log.debug("User not found, redirecting to registration");
}
}
@Bean
public UserDetailsService userDetailsService() {
return email -> Optional.of(appUserService.getUserByEmail(email))
.orElseThrow(() -> new UsernameNotFoundException("AppUser not found"));
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationProvider authenticationProvider() {
var authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService());
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
return configuration.getAuthenticationManager();
}
}
package com.web.photo.app.route.login;
@Route(value = "login", layout = AppLayoutNavbar.class)
@AnonymousAllowed
@PageTitle("Login")
public class LoginView extends VerticalLayout implements BeforeEnterObserver {
private final LoginForm login = createLoginForm();
@Override
public void beforeEnter(BeforeEnterEvent beforeEnterEvent) {
// inform the user about an authentication error
if(beforeEnterEvent.getLocation()
.getQueryParameters()
.getParameters()
.containsKey("error")) {
login.setError(true);
}
}
public LoginView(){
var loginLinkGoogle = getLoginLinkGoogle();
add(new H1("Web Photo App"), login, loginLinkGoogle);
}
private Anchor getLoginLinkGoogle() {
var loginLinkGoogle = new Anchor(AuthUtil.OAUTH_URL_GOOGLE, "Login with Google");
loginLinkGoogle.getElement().setAttribute("router-ignore", true);
getStyle().set("padding", "200px");
setAlignItems(Alignment.CENTER);
addClassName("login-view");
setSizeFull();
setAlignItems(Alignment.CENTER);
setJustifyContentMode(JustifyContentMode.CENTER);
return loginLinkGoogle;
}
private LoginForm createLoginForm() {
var login = new LoginForm();
login.setAction("login");
login.setForgotPasswordButtonVisible(false);
login.setI18n(createI18n());
return login;
}
private LoginI18n createI18n() {
var i18n = LoginI18n.createDefault();
i18n.getForm().setUsername("Email");
i18n.getErrorMessage().setUsername("Email is required");
return i18n;
}
}
package com.web.photo.app.util;
@NoArgsConstructor(access = lombok.AccessLevel.PRIVATE)
public class AuthUtil {
public static final String OAUTH_URL_GOOGLE = "/oauth2/authorization/google";
public static Authentication getAuthentication() {
return SecurityContextHolder.getContext().getAuthentication();
}
public static boolean isAnonymous() {
var auth = getAuthentication();
return (auth instanceof AnonymousAuthenticationToken);
}
public static AppUser getCurrentUser() {
var auth = getAuthentication();
if (auth instanceof UsernamePasswordAuthenticationToken) {
return (AppUser) auth.getPrincipal();
}
throw new IllegalStateException("User not found!");
}
public static String getCurrentUserEmail() {
return getCurrentUser().getEmail();
}
public static void setSecurityContext(AppUser userInfo) {
final SecurityContext context = SecurityContextHolder.getContext();
final Authentication auth = new UsernamePasswordAuthenticationToken(userInfo, userInfo.getPassword(),
userInfo.getAuthorities());
context.setAuthentication(auth);
SecurityContextHolder.setContext(context);
}
public static void logout() {
SecurityContextHolder.clearContext();
var logoutHandler = new SecurityContextLogoutHandler();
VaadinSession.getCurrent().getSession().invalidate();
logoutHandler.logout(VaadinServletRequest.getCurrent().getHttpServletRequest(), null, null);
}
public static void refreshUser(AppUser newUser) {
var auth = getAuthentication();
var newAuth = new UsernamePasswordAuthenticationToken(newUser, auth.getCredentials(), auth.getAuthorities());
setSecurityContext(((AppUser) newAuth.getPrincipal()));
}
}