Battalgazi
Battalgazi

Reputation: 379

Serve Angular 2 project from static folder with Spring Security

So I have a working frontend with Angular2 and a working backend with Java and what I do is to serve my index.html from the static folder which also contains all my frontend resources. The problem is that when I tried to add Spring Security to the backend the resources are not accessible anymore because of the @EnableWebSecurity annotation. When I navigate to my localhost http://localhost:8080/ the index.html is not served. But if I access it or any other resource writing the path manually, it loads. I wouldn't like to serve my frontend differently, is there any way to do this from the static? I tried the following:

Here my security configuration:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@ComponentScan(basePackages = {"com.ramso.restapi.security"})
public class SecurityConfig extends WebSecurityConfigurerAdapter {

private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);

public static final String REMEMBER_ME_KEY = "rememberme_key";

public SecurityConfig() {
    super();
    logger.info("loading SecurityConfig ................................................ ");
}

@Autowired
private UserDetailsService userDetailsService;

@Autowired
private RestUnauthorizedEntryPoint restAuthenticationEntryPoint;


@Autowired
private AuthenticationSuccessHandler restAuthenticationSuccessHandler;

@Autowired
private AuthenticationFailureHandler restAuthenticationFailureHandler;

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService);
}


@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/front/**","/index.html");
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .headers().disable()
        .csrf().disable()
        .authorizeRequests()
            .antMatchers("/failure").permitAll()
            .anyRequest().authenticated()
            .and()
        .exceptionHandling()
            .authenticationEntryPoint(restAuthenticationEntryPoint)
            .and()
        .formLogin()
            .loginPage("/login")
            .loginProcessingUrl("/authenticate")
            .successHandler(restAuthenticationSuccessHandler)
            .failureHandler(restAuthenticationFailureHandler)
            .usernameParameter("username")
            .passwordParameter("password")
            .permitAll()
            .and()
        .logout()
            .logoutUrl("/logout")
            .logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler())
            .deleteCookies("JSESSIONID")
            .permitAll()
            .and();

}
}

WebMvcConfiguration:

@Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {

@Override
public void addViewControllers(ViewControllerRegistry registry) {
//registry.addViewController("/").setViewName("front/index.html");
//registry.addViewController("/").setViewName("forward:/index.html");
    registry.addViewController("/").setViewName("redirect:/index.html");

registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}

}

Application.java:

@SpringBootApplication
public class Application {

public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
}
}

Upvotes: 4

Views: 5351

Answers (2)

Tom
Tom

Reputation: 3850

In the class that extends WebSecurityConfigurerAdapter you can add the following:

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/front/**");
}

Any ant matcher you put in web.ignoring() method should be ignored by spring security.

By default the static content should be placed in one of the following directories under src/main/resources (from spring boot - static content):

/META-INF/resources/
/resources/
/static/
/public/

Then any ant matcher is checked in front of the sub folders.

For example, if your static content is in src/main/resources/static/front the ant matcher /front/** should ignore all resources in that sub-folder.

Also, in order to expose index.html you should place it in src/main/resources/static and add something like the following class in order to expose it as the main resource when accessing your site:

@Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index.html");
        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
    }

}

and of course add it as an ant matcher: web.ignoring().antMatchers("/*", "/front/**", "index.html");

/* will not allow all, /** does that. make sure you place your API's on a secure endpoint like /api or something like that and the static content on an ignored path.

Upvotes: 7

Leon Radley
Leon Radley

Reputation: 7682

The problem could be that angular-cli puts all resources at the root of your app. (Though I'm not sure you are using angular-cli)

But lets entertain the notion.

angular-cli outputs something like

/inline.8faab088ca0e1cca9031.bundle.js
/main.c7b67df9d7c42383815c.bundle.js
/polyfills.c234d2c8820869e3c698.bundle.js
/styles.d41d8cd98f00b204e980.bundle.css
/vendor.f0f36dacdf3fba21c295.bundle.js

This makes it very hard for you to apply a spring security antMatcher.

angular-cli has a configuration called --deploy-url=/ui/ which will mean that all script files point to a directory called /ui/

<script type="text/javascript" src="/ui/inline.4c30f42211c1d30d3dd3.bundle.js"></script>
<script type="text/javascript" src="/ui/polyfills.c234d2c8820869e3c698.bundle.js"></script>
<script type="text/javascript" src="/ui/vendor.f0f36dacdf3fba21c295.bundle.js"></script>
<script type="text/javascript" src="/ui/main.c7b67df9d7c42383815c.bundle.js"></script>

Then you should be able to ignore the path as Tom suggests.

Upvotes: 1

Related Questions