Spring Security Ajax login

后端 未结 4 983
再見小時候
再見小時候 2020-12-08 03:35

I have implemented this security proccess in my project: Spring Security 3 - MVC Integration Tutorial (Part 2).

My problem is that I need to turn it into an Ajax-ba

相关标签:
4条回答
  • 2020-12-08 03:47

    You can use HttpServletRequest.login(username,password) to login, just like:

    @Controller
    @RequestMapping("/login")
    public class AjaxLoginController {
    
        @RequestMapping(method = RequestMethod.POST)
        @ResponseBody
        public String performLogin(
            @RequestParam("username") String username,
            @RequestParam("password") String password,
            HttpServletRequest request, HttpServletResponse response) {
        try {
            request.login(username,password);
            return "{\"status\": true}";
        } catch (Exception e) {
            return "{\"status\": false, \"error\": \"Bad Credentials\"}";
        }
    }
    
    0 讨论(0)
  • 2020-12-08 03:52

    Spring is shifting away from XML based configurations and towards Java @Configuration classes. Below is @Configuration version of the setup explained in the post above (Spring Security Ajax login). Steps 2 & 3 remain the same, replace Step 1 with this code. The order is once again important, more specific definitions needs to be loaded before more generic ones, use @Order(1) and @Order(2) to control that.

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.annotation.Order;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.builders.WebSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
    import org.springframework.security.web.savedrequest.RequestCache;
    
    @Configuration
    @EnableWebSecurity
    public class WebMvcSecurityConfiguration extends WebSecurityConfigurerAdapter {
    
        @Bean(name = "requestCache")
        public RequestCache getRequestCache() {
            return new HttpSessionRequestCache();
        }
    
        @Configuration
        @Order(1)
        public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
    
                @Autowired private RequestCache requestCache;
    
                @Override
                protected void configure(HttpSecurity http) throws Exception {
                    http
                        .regexMatcher("/rest.*")
                        .authorizeRequests()
                            .antMatchers("/rest/calendar/**")
                                .hasAuthority("ROLE_USER")
                            .antMatchers("/rest/**")
                                .permitAll()
                            .and()
                       .headers()
                            .xssProtection()
                            .and()
                       .logout()
                           .logoutUrl("/rest/security/logout-url")
                           .and()
                        .requestCache()
                            .requestCache(requestCache)
                            .and()
                        .formLogin()
                            .loginProcessingUrl("/rest/security/login-processing")
                            .loginPage("/rest/security/login-page")
                            .failureUrl("/rest/security/authentication-failure")
                            .defaultSuccessUrl("/rest/security/default-target", false)
                            .and()
                        .httpBasic();
               }
        }
    
        @Configuration
        @Order(2)
        public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
    
            @Autowired private RequestCache requestCache;
    
           @Override
           protected void configure(HttpSecurity http) throws Exception {
               http
                    .authorizeRequests()
                        .regexMatchers("/calendar/.*")
                            .hasAuthority("ROLE_USER")
                        .regexMatchers("/.*")
                            .permitAll()
                       .and()
                   .logout()
                       .logoutUrl("/security/j_spring_security_logout")
                       .and()
                    .requestCache()
                        .requestCache(requestCache)
                        .and()
                    .formLogin()
                        .loginProcessingUrl("/security/j_spring_security_check")
                        .loginPage("/login")
                        .failureUrl("/login?login_error=t" )
                        .and()
                    .httpBasic();
           }
        }
    
        @Override
        public void configure(WebSecurity web) throws Exception {
            web
                .ignoring()
                    .antMatchers("/resources/**")
                    .antMatchers("/sitemap.xml");
        }
    }
    
    0 讨论(0)
  • 2020-12-08 03:55

    This is an old post, but it still comes up as one of the top results for "spring security ajax login," so I figured I'd share my solution. It follows Spring Security standards and is pretty simple to setup, the trick is to have 2 <http> elements in your security configuration, one for REST/Ajax and one for the rest of the app (regular HTML pages). The order in which <http>'s appear is important, it has to go from more specific to more generic URLs, just like <url-intercept> elements inside of a <http>.

    Step 1: Setup Two Separate <http>'s

    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/security" 
        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:beans="http://www.springframework.org/schema/beans" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
            http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
    
        <!-- a shared request cache is required for multiple http elements -->
        <beans:bean id="requestCache" class="org.springframework.security.web.savedrequest.HttpSessionRequestCache" />
    
        <!-- remove security from static resources to avoid going through the security filter chain -->
        <http pattern="/resources/**" security="none" />
    
        <!-- http config for REST services (AJAX interface) 
        =================================================== -->
        <http auto-config="true" use-expressions="true" pattern="/rest/**">
            <!-- login configuration 
                login-processing-url="/rest/security/login-processing" front-end AJAX requests for authentication POST to this URL
                login-page="/rest/security/login-page" means "authentication is required"
                authentication-failure-url="/rest/security/authentication-failure" means "authentication failed, bad credentials or other security exception"
                default-target-url="/rest/security/default-target" front-end AJAX requests are redirected here after success authentication
            -->
            <form-login 
                login-processing-url="/rest/security/login-processing" 
                login-page="/rest/security/login-page" 
                authentication-failure-url="/rest/security/authentication-failure" 
                default-target-url="/rest/security/default-target" 
                always-use-default-target="true" />
            <logout logout-url="/rest/security/logout-url" />
    
            <!-- REST services can be secured here, will respond with JSON instead of HTML -->
            <intercept-url pattern="/rest/calendar/**" access="hasRole('ROLE_USER')" />
    
            <!-- other REST intercept-urls go here -->
    
            <!-- end it with a catch all -->
            <intercept-url pattern="/rest/**" access="isAuthenticated()" />
    
            <!-- reference to the shared request cache -->
            <request-cache ref="requestCache"/>
        </http>
    
        <!-- http config for regular HTML pages
        =================================================== -->
        <http auto-config="true" use-expressions="true">
            <form-login 
                login-processing-url="/security/j_spring_security_check" 
                login-page="/login" 
                authentication-failure-url="/login?login_error=t" />
            <logout logout-url="/security/j_spring_security_logout" />
    
            <intercept-url pattern="/calendar/**" access="hasRole('ROLE_USER')" />
    
            <!-- other intercept-urls go here -->
    
            <!-- in my app's case, the HTML config ends with permitting all users and requiring HTTPS
                 it is always a good idea to send sensitive information like passwords over HTTPS -->
            <intercept-url pattern="/**" access="permitAll" requires-channel="https" />
    
            <!-- reference to the shared request cache -->
            <request-cache ref="requestCache"/>
        </http>
    
        <!-- authentication manager and other configuration go below -->
    </beans:beans>
    

    Step 2: REST Authentication Controller

    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    
    import flexjson.JSONSerializer;
    
    @Controller
    @RequestMapping(value = "/rest/security")
    public class RestAuthenticationController {
    
        public HttpHeaders getJsonHeaders() {
            HttpHeaders headers = new HttpHeaders();
            headers.add("Content-Type", "application/json");
            return headers;
        }
    
        @RequestMapping(value="/login-page", method = RequestMethod.GET)
        public ResponseEntity<String> apiLoginPage() {
            return new ResponseEntity<String>(getJsonHeaders(), HttpStatus.UNAUTHORIZED);
        }
    
        @RequestMapping(value="/authentication-failure", method = RequestMethod.GET)
        public ResponseEntity<String> apiAuthenticationFailure() {
            // return HttpStatus.OK to let your front-end know the request completed (no 401, it will cause you to go back to login again, loops, not good)
            // include some message code to indicate unsuccessful login
            return new ResponseEntity<String>("{\"success\" : false, \"message\" : \"authentication-failure\"}", getJsonHeaders(), HttpStatus.OK);
        }
    
        @RequestMapping(value="/default-target", method = RequestMethod.GET)
        public ResponseEntity<String> apiDefaultTarget() {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            // exclude/include whatever fields you need
            String userJson = new JSONSerializer().exclude("*.class", "*.password").serialize(authentication);
            return new ResponseEntity<String>(userJson, getJsonHeaders(), HttpStatus.OK);
        }
    }
    

    Step 3: Submit AJAX form and process the response, required jQuery's ajaxForm library

    <form action="/rest/security/login-processing" method="POST">
    ...
    </form>
    
    $('form').ajaxForm({
        success: function(response, statusText, xhr, $form)  {
            console.log(response);
            if(response == null || response.username == null) {
                alert("authentication failure");
            } else {
                // response is JSON version of the Spring's Authentication
                alert("authentication success");
            }
        },
        error: function(response, statusText, error, $form)  { 
            if(response != null && response.message == "authentication-failure") {
                alert("authentication failure");
            }
        }
    });
    
    0 讨论(0)
  • 2020-12-08 04:03

    It depends on the implementation of your ajax-login. In any case, I guess you need to implement a custom filter. There are two good tutorials for using Spring Security with ExtJs:

    Integrating Spring Security 3 with Extjs

    Integrating Spring Security with ExtJS Login Page

    It should work very similar for other Ajax login-forms.

    0 讨论(0)
提交回复
热议问题