Logo

dev-resources.site

for different kinds of informations.

Spring Boot with VueJS with Spring Security

Published at
9/17/2024
Categories
springboot
spring
springsecurity
vue
Author
mkp_bijit
Author
9 person written this
mkp_bijit
open
Spring Boot with VueJS with Spring Security

This article was originally published in https://portfolio.bijit.xyz/blogs/spring-boot-with-vue-security-on

Configuring Spring Boot With Vue JS

Dan Vega has an wonderful article on configuring Vue on the frontend and Spring Boot on the backend using a monolithic approach, this design is suitable for a team of full-stack developers who will be working on both sides of the application.

I would recommend to go through the article first. https://www.danvega.dev/blog/full-stack-java.

What happens after adding Spring Security

After Integrating Spring Security into the application, by default, Spring Security will protect all the routes, which will lead to frontend path (/) getting protected as well.

This means that any request made to the application require authentication, including requests to frontend which is not what we want.

Solution

So what can we do? Whitelisting the root (/) path is not a good idea beacuse doing so will also expose the protected controller to unauthorized user. A more secure and recommended approach is to serve frontend from a different path, such as /app and then whitelist the /app path in Spring Security configuration to allow unauthenticated access to frontend.

Vue Configuration

So let's add the configuration in Vue application that will make the vue application be served from /app path. In /frontend folder edit vue.config.js file

const { defineConfig } = require('@vue/cli-service')

module.exports = defineConfig({
  transpileDependencies: true,
  publicPath: '/app/', // [!code focus]
  devServer: {
    client: {
      overlay: false,
    },
    port: 3000,
    proxy: {
      '/api': {
        target: 'http://192.168.43.28:8080',
        ws: true,
        changeOrigin: true
      }
    }
  }
})
Enter fullscreen mode Exit fullscreen mode

It will make the app to be served from a sub-path. For example, if the app is deployed at https://www.foobar.com/my-app/, set publicPath to '/my-app/'.

Spring Boot configuration

As discussed earlier, by default, Spring Boot serves all static content under the root part of the request, /**. We can change it via the spring.mvc.static-path-pattern configuration property.

Change your application.properties

spring.mvc.static-path-pattern=/app/*
Enter fullscreen mode Exit fullscreen mode

or if you are using yaml configuration change your application.yaml or application.yml

spring:
  mvc:
    static-path-pattern: /app/**
Enter fullscreen mode Exit fullscreen mode

Now that we have made the frontend to be served from "/app" sub-path, we need to whitelist the path.Made the following changes as per configuration.

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableMethodSecurity
public class SecurityConfiguration {
    private static final String[] WHITE_LIST_URL = {
            "/api/v1/auth/**",
            "/app/**",  // [!code focus]
    };
    private final JWTAuthenticationFilter jwtAuthFilter;
    private final AuthenticationProvider authenticationProvider;
    private final LogoutHandler logoutHandler;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests(req ->
                        req
                                .requestMatchers(WHITE_LIST_URL).permitAll() // [!code focus]
                                .requestMatchers("/api/v1/user/**").hasAnyRole(ADMIN.name(),USER.name())
                                .requestMatchers("/api/v1/admin/**").hasAnyRole(ADMIN.name())
                                .anyRequest()
                                .authenticated()
                )
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authenticationProvider(authenticationProvider)
                .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
        ;

        return http.build();
    }
}
Enter fullscreen mode Exit fullscreen mode

Your configuration file may be different, we just need to whitelist the /app. Here is my configuration on gitlab.

🎉 we have done it.

But wait, try to refresh the frontend and it will most probably fail. Why this happens?

This is because our vuejs application is pure client side SPA(Single Page Application), there is only one index.html file, and every request is hitting that html file and all subsequent requests are handled by the client-side JavaScript code. When we refresh the page, the browser sends a request to the server for the requested URL, but since there is no file for that URL, the server returns a 404 error.This is why refreshing the page in a Vue.js SPA can result in a failure.

So, if we redirect every request coming to /app/** we can forward it to index.html file it should work.
Create an FrontendForwardController for that.

@Controller
public class FrontendForwardController {
    //    TODO
    //    Better regex needed
    @GetMapping({ "/app","/app/","/app/problems/**","/app/problems","/app/auth","/app/auth/**","/app/admin","/app/admin/**"})
    public String forward() {
        return "forward:/app/index.html";
    }
}

Enter fullscreen mode Exit fullscreen mode

The above controller forwarding some frontend request like /app or /app/problems/** to index.html.

There is a problem though in this approach, whenever we add a new route to our frontend we need to allow it here at FrontendForwardController to forward the request to index.html.

public class FrontendForwardController {
    @GetMapping("/app/**") // [!code error]
    public String forward(){
        return "forward:/app/index.html";
    }
}
Enter fullscreen mode Exit fullscreen mode

We can't make the FrontendForwardController like above, because it will result in an endless recursion.

That's all.
Happy coding
Bijit

springsecurity Article's
30 articles in total
Favicon
Understanding Spring Security and OAuth 2.0
Favicon
Spring Oauth2 - App-Token based Hybrid Token Verification Methods
Favicon
App-Token based easy OAuth2 implementation built to grow with Spring Boot
Favicon
Apache wicket with spring boot example application: notice board
Favicon
Spring Security: CSRF protection
Favicon
Mastering End-to-End Transactional Functionality in Spring Boot with Examples
Favicon
Spring Security: Redirect to login page if access pages which is for authorized user only
Favicon
Understanding the Spring Security Architecture
Favicon
Spring security
Favicon
Implementing Token-Based Authentication in Spring Boot Using Spring Security, JWT, and JDBC Template
Favicon
Implementing One-Time Token Authentication with Spring Security
Favicon
Login system with JWT token and email reset password
Favicon
Keycloak and Spring Boot: The Ultimate Guide to Implementing Single Sign-On
Favicon
Securing Your Spring Boot Application with Spring Security
Favicon
Guia básico de Spring Security
Favicon
OAuth2.0 Spring Boot
Favicon
Spring Boot Caching Simplified: How to Use JetCache Effectively
Favicon
OAuth 2 Token Exchange with Spring Security and Keycloak
Favicon
Implementing Spring Security in Microservices Architecture: A Deep Dive
Favicon
Mastering Spring Security: A Comedy of Errors (and Authentication)
Favicon
Spring Security For Beginners — Part 2
Favicon
Spring Boot with VueJS with Spring Security
Favicon
Spring Security: Protecting Your App from Everyone (Including You!)
Favicon
What is the CORS ?
Favicon
Spring Security For Beginners — Part 1
Favicon
Spring Boot WebSockets: Socket.io + Authentication + Postman
Favicon
Roadmap to Mastering the Spring Framework 🚀
Favicon
Spring Security 103: Exploring Default Security Configuration
Favicon
Spring Security 102: From Setup to Secure Endpoints in Spring Boot
Favicon
Spring Security 101: Understanding the Basics

Featured ones: