0
votes

I have a web application + a set of rest APIs created with spring. It is essentially some html pages sending ajax requests to the rest server. The structure looks somewhat like this:

myWebapp -> src/main/webapp/public (public pages)
myWebapp -> src/main/webapp/resources (non - public pages, available only after login)

I need to secure some of the static content (non-public above) and the rest APIs (Preferably with LDAP, but that's not important). How do i configure the filters and/or spring security intercepts so that:

  1. Same credentials work for both static content and rest calls.
  2. User can login via a login page, and for further rest calls uses some token or something returned from server.

I have checked spring security schemes for rest API's and also found some resources on securing static content, but not able to figure out how to fit this together as above.

1
what is the URL path for your restful services? - Anantha Sharma
@AnanthaSharma Rest resources are served at /rest/api/<specific paths>. While the static pages, css, js etc. at usual /public/js/blah.js etc (public) and /resources/user/myhome.html (non public) - Bhawesh Ji

1 Answers

1
votes

I guess you want to have two sets of resources. One of them is open for public access and available at, say, /public context and the other is protected and available at /protected.

First, you should create some Resource Handlers in your Web Configuration:

@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
    // other stuffs

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/public/**").addResourceLocations("classpath:/public/");
        registry.addResourceHandler("/protected/**").addResourceLocations("classpath:/resources/");
    }
}

This way all the static contents in /public directory will be served at /public/** endpoint and /protected/** endpoint will serve files in the /resources directory.

Then you should configure Spring Security in order to protect /protected/** endpoint:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    // other stuffs

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                    .antMatchers("/public/**").permitAll()
                    .antMatchers("/protected/**").authenticated()
                    .anyRequest().authenticated();
    }
}

Update For REST endpoints you can either use same the matchers or have finer grain control with Method Level Security. In order to enable method level security, add @EnableGlobalMethodSecurity(prePostEnabled = true) to your SecurityConfig. Then you can use PrePost annotations on hanlder methods, like following:

@RestController
@RequestMapping("/greet")
public class GreetingService {
    // it's a public rest endpoint
    @PreAuthorize("permitAll()")
    @RequestMapping("/public")
    public void doGreetToPublicUsers() {...}

    // it's a protected rest endpoint
    @PreAuthorize("isAuthenticated()")
    @RequestMapping("/protected")
    public void doGreetToProtectedUsers() {...}

    // it's a role protected rest endpoint
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @RequestMapping("/admin")
    public void justForAdmin() {...}
}