简体   繁体   中英

Securing a REST Api with Spring Security

I'm new to Spring Security and I'm trying to secure a REST api inside my app. I have the app URIS and then I have an URI like "/api/v1/" to my rest api.

I have secured my application with username/password authentication and it's working fine, but now I want to secure my REST api returning 401 Unauthorized if the user isn't authenticated, but I don't know how to keep the two authentications together.

What it's the way to go here?

PS: I'm using Spring MVC with Spring Security

This is my Spring Security configuration right now:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private AccountService accountService;

    @Bean
    public TokenBasedRememberMeServices rememberMeServices() {
        return new TokenBasedRememberMeServices("remember-me-key", accountService);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new StandardPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.eraseCredentials(true).userDetailsService(accountService).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/", "/favicon.ico", "/resources/**", "/signup").permitAll().anyRequest()
                .authenticated()
                .and().formLogin().loginPage("/signin").permitAll().failureUrl("/signin?error=1")
                .loginProcessingUrl("/authenticate")
                .and().logout().logoutUrl("/logout").permitAll().logoutSuccessUrl("/signin?logout")
                .and().rememberMe().rememberMeServices(rememberMeServices()).key("remember-me-key")
                .and().csrf();
    }

    @Bean(name = "authenticationManager")
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

So you want to have form login plus secure rest api right?

jhipster can generate such project structure. Let me give some example code for achieving this if you don't want to use jhipster (it's pretty cool though, I recommend)

to return 401 for unauthorized you need something like this:

/**
 * Returns a 401 error code (Unauthorized) to the client.
 */
@Component
public class Http401UnauthorizedEntryPoint implements AuthenticationEntryPoint {

    private final Logger log = LoggerFactory.getLogger(Http401UnauthorizedEntryPoint.class);

    /**
     * Always returns a 401 error code to the client.
     */
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException arg2)
        throws IOException,
        ServletException {

        log.debug("Pre-authenticated entry point called. Rejecting access");
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Access Denied");
    }
}

then inject and add this to your SecurityConfig.configure(HttpSecurity http) method:

http.authenticationEntryPoint(authenticationEntryPoint)

plus since REST requests are ajax requests you also need ajax entry points:

/**
 * Returns a 401 error code (Unauthorized) to the client, when Ajax authentication fails.
 */
@Component
public class AjaxAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
        AuthenticationException exception) throws IOException, ServletException {

        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication failed");
    }
}


/**
 * Spring Security success handler, specialized for Ajax requests.
 */
@Component
public class AjaxAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
        Authentication authentication)
        throws IOException, ServletException {

        response.setStatus(HttpServletResponse.SC_OK);
    }
}

/**
 * Spring Security logout handler, specialized for Ajax requests.
 */
@Component
public class AjaxLogoutSuccessHandler extends AbstractAuthenticationTargetUrlRequestHandler
    implements LogoutSuccessHandler {

    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
        Authentication authentication)
        throws IOException, ServletException {
        response.setStatus(HttpServletResponse.SC_OK);
    }
}

add them to security config too:

http.successHandler(ajaxAuthenticationSuccessHandler)
    .failureHandler(ajaxAuthenticationFailureHandler)
    .logoutSuccessHandler(ajaxLogoutSuccessHandler)

All credit goes to the amazing jhipster authors.

You can use expression based access control http://docs.spring.io/spring-security/site/docs/3.0.x/reference/el-access.html

Something like,

<intercept-url pattern=/** access="isFullyAuthenticated()/>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM