Spring Security Disable Login Page / Redirect

前端 未结 5 2493
旧巷少年郎
旧巷少年郎 2021-02-18 13:58

Is there a way to disable the redirect for Spring Security and the login page. My requirements specify the login should be part of the navigation menu.

Example:

相关标签:
5条回答
  • 2021-02-18 14:34

    The redirect behavior comes from SavedRequestAwareAuthenticationSuccessHandler which is the default success handler. Thus an easy solution to remove the redirect is to write your own success handler. E.g.

    http.formLogin().successHandler(new AuthenticationSuccessHandler() {
        @Override
        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
           //do nothing
        }
    });
    
    0 讨论(0)
  • 2021-02-18 14:43

    When a browser gets a 401 with "WWW-Authetication: Basic ... ", it pops up a Dialog. Spring Security sends that header unless it sees "X-Requested-With" in the request.

    You should send "X-Requested-With: XMLHttpRequest" header for all requests, this is an old fashioned way of saying - I am an AJAX request.

    0 讨论(0)
  • 2021-02-18 14:50

    On my project I implemented it for the requirements:

    1) For rest-request 401 status if user is not authorized

    2) For simple page 302 redirect to login page if user is not authorized

    public class AccessDeniedFilter extends GenericFilterBean {
    
    @Override
    public void doFilter(
            ServletRequest request,
            ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
    
        try {
            filterChain.doFilter(request, response);
        } catch (Exception e) {
    
            if (e instanceof NestedServletException &&
                    ((NestedServletException) e).getRootCause() instanceof AccessDeniedException) {
    
                HttpServletRequest rq = (HttpServletRequest) request;
                HttpServletResponse rs = (HttpServletResponse) response;
    
                if (isAjax(rq)) {
                    rs.sendError(HttpStatus.FORBIDDEN.value());
                } else {
                    rs.sendRedirect("/#sign-in");
                }
            }
        }
    }
    
    private Boolean isAjax(HttpServletRequest request) {
        return request.getContentType() != null &&
               request.getContentType().contains("application/json") &&
               request.getRequestURI() != null &&
               (request.getRequestURI().contains("api") || request.getRequestURI().contains("rest"));
        }
    }
    

    And enable the filter:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
       ...
        http
                .addFilterBefore(new AccessDeniedFilter(),
                        FilterSecurityInterceptor.class);
       ...
    }
    

    You can change handle AccessDeniedException for you requirements in the condition:

    if (isAjax(rq)) {
        rs.sendError(HttpStatus.FORBIDDEN.value());
    } else {
        rs.sendRedirect("/#sign-in");
    }
    
    0 讨论(0)
  • 2021-02-18 14:52

    For annotation based settings use the following:

    .defaultSuccessUrl("/dashboard",true)
    
    0 讨论(0)
  • 2021-02-18 15:00

    You need to disable redirection in a couple of different places. Here's a sample based on https://github.com/Apress/beg-spring-boot-2/blob/master/chapter-13/springboot-rest-api-security-demo/src/main/java/com/apress/demo/config/WebSecurityConfig.java

    In my case, I don't return json body but only HTTP status to indicate success/failure. But you can further customize the handlers to build the body. I also kept CSRF protection on.

    @Configuration
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
        @Autowired
        public void initialize(AuthenticationManagerBuilder auth, DataSource dataSource) throws Exception {
            // here you can customize queries when you already have credentials stored somewhere
            var usersQuery = "select username, password, 'true' from users where username = ?";
            var rolesQuery = "select username, role from users where username = ?";
            auth.jdbcAuthentication()
                    .dataSource(dataSource)
                    .usersByUsernameQuery(usersQuery)
                    .authoritiesByUsernameQuery(rolesQuery)
            ;
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                // all URLs are protected, except 'POST /login' so anonymous user can authenticate
                .authorizeRequests()
                    .antMatchers(HttpMethod.POST, "/login").permitAll()
                    .anyRequest().authenticated()
    
                // 401-UNAUTHORIZED when anonymous user tries to access protected URLs
                .and()
                    .exceptionHandling()
                    .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
    
                // standard login form that sends 204-NO_CONTENT when login is OK and 401-UNAUTHORIZED when login fails
                .and()
                    .formLogin()
                    .successHandler((req, res, auth) -> res.setStatus(HttpStatus.NO_CONTENT.value()))
                    .failureHandler(new SimpleUrlAuthenticationFailureHandler())
    
                // standard logout that sends 204-NO_CONTENT when logout is OK
                .and()
                    .logout()
                    .logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler(HttpStatus.NO_CONTENT))
    
                // add CSRF protection to all URLs
                .and()
                    .csrf()
                    .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
            ;
        }
    }
    

    Here's a deep explanation of the whole process, including CSRF and why you need a session: https://spring.io/guides/tutorials/spring-security-and-angular-js/

    Scenarios that I tested:

    happy path
    
    GET /users/current (or any of your protected URLs)
     request --> no cookie
     <- response 401 + cookie XSRF-TOKEN
    
    POST /login
     -> header X-XSRF-TOKEN + cookie XSRF-TOKEN + body form with valid username/password
     <- 204 + cookie JSESSIONID
    
    GET /users/current
     -> cookie JSESSIONID
     <- 200 + body with user details
    
    POST /logout
     -> header X-XSRF-TOKEN + cookie XSRF-TOKEN + cookie JSESSIONID
     <- 204
    
    === exceptional #1: bad credentials
    
    POST /login
     -> header X-XSRF-TOKEN + cookie XSRF-TOKEN + body form with bad username/password
     <- 401
    
    === exceptional #2: no CSRF at /login (like a malicious request)
    
    POST /login
     -> cookie XSRF-TOKEN + body form with valid username/password
     <- 401 (I would expect 403, but this should be fine)
    
    === exceptional #3: no CSRF at /logout (like a malicious request)
    
    (user is authenticated)
    
    POST /logout
     -> cookie XSRF-TOKEN + cookie JSESSIONID + empty body
     <- 403
    
    (user is still authenticated)
    
    0 讨论(0)
提交回复
热议问题