Spring Security禁用登录页面/重定向

gre*_*fox 11 spring spring-security

有没有办法禁用Spring Security和登录页面的重定向.我的要求指定登录应该是导航菜单的一部分.

例:

在此输入图像描述

因此,没有专用的登录页面.登录信息需要通过Ajax提交.如果发生错误,则应返回指定错误的JSON并使用正确的HTTP状态代码.如果身份验证检出它应该返回200然后javascript可以从那里处理它.

我希望这是有道理的,除非有更简单的方法来实现Spring Security.我对Spring Security没有多少经验.我认为这必须是一种常见的做法,但我没有找到太多.

当前的弹簧安全配置

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/", "/public/**").permitAll()
                .antMatchers("/about").permitAll()
                .anyRequest().fullyAuthenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .failureUrl("/login?error")
                .usernameParameter("email")
                .permitAll()
                .and()
                .logout()
                .logoutUrl("/logout")
                .deleteCookies("remember-me")
                .logoutSuccessUrl("/")
                .permitAll()
                .and()
                .rememberMe();
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(userDetailsService)
                .passwordEncoder(new BCryptPasswordEncoder());
    }
Run Code Online (Sandbox Code Playgroud)

更新:

我尝试使用HttpBasic()然后它要求登录信用无关紧要什么及其丑陋的浏览器弹出窗口是最终用户不能接受的.看起来我可能需要扩展AuthenticationEntryPoint.

在一天结束时,我需要Spring安全性发回JSON,说验证成功或失败.

ben*_*ben 9

重定向行为来自SavedRequestAwareAuthenticationSuccessHandler,它是默认的成功处理程序.因此,删除重定向的简单解决方案是编写自己的成功处理程序.例如

http.formLogin().successHandler(new AuthenticationSuccessHandler() {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
       //do nothing
    }
});
Run Code Online (Sandbox Code Playgroud)


And*_*dré 8

您需要在几个不同的地方禁用重定向。这是基于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

就我而言,我不返回 json 正文,而只返回 HTTP 状态来指示成功/失败。但是您可以进一步自定义处理程序以构建主体。我还保持 CSRF 保护。

@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())
        ;
    }
}
Run Code Online (Sandbox Code Playgroud)

下面是对整个过程的深入解释,包括CSRF以及为什么需要会话:https : //spring.io/guides/tutorials/spring-security-and-angular-js/

我测试的场景:

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)
Run Code Online (Sandbox Code Playgroud)

  • 这是金子。感谢您链接该文章。 (2认同)

Ant*_*rov 5

在我的项目中,我实现了以下要求:

1)如果用户无权获得休息请求401状态

2)如果未授权用户,则对于简单页面302重定向到登录页面

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"));
    }
}
Run Code Online (Sandbox Code Playgroud)

并启用过滤器:

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

您可以在以下情况下根据需要更改句柄AccessDeniedException:

if (isAjax(rq)) {
    rs.sendError(HttpStatus.FORBIDDEN.value());
} else {
    rs.sendRedirect("/#sign-in");
}
Run Code Online (Sandbox Code Playgroud)


Sid*_*ati 3

当浏览器收到带有“WWW-Authetication: Basic ...”的 401 错误时,它会弹出一个对话框。Spring Security 会发送该标头,除非它在请求中看到“X-Requested-With”。

您应该为所有请求发送“X-Requested-With: XMLHttpRequest”标头,这是一种老式的说法 - 我是一个 AJAX 请求。