当前位置: 首页 > 知识库问答 >
问题:

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

谭献
2023-03-14

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

例子:

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

我希望这是有意义的,除非有任何更简单的方法可以通过Spring Security实现这一点。我对Spring Security没有太多经验。我想这应该是一种常见的做法,但我没有发现太多。

当前Spring安全配置

@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());
    }

更新:

我试过使用HttpBasic(),但不管是什么,它都会要求登录凭据,而且会弹出丑陋的浏览器弹出窗口,这是最终用户无法接受的。看起来我可能需要扩展AuthenticationEntryPoint。

最后,我需要Spring security发回JSON,说明身份验证成功或失败。

共有3个答案

莫宁
2023-03-14

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

1)如果用户未被授权,则为Rest请求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"));
    }
}

并启用过滤器:

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

您可以在以下条件下为您的要求更改处理AccessDeniedException:

if (isAjax(rq)) {
    rs.sendError(HttpStatus.FORBIDDEN.value());
} else {
    rs.sendRedirect("/#sign-in");
}
子车青青
2023-03-14

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

以下是对整个过程的深入解释,包括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)
焦宏硕
2023-03-14

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

http.formLogin().successHandler(new AuthenticationSuccessHandler() {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
       //do nothing
    }
});
 类似资料:
  • 记录器文件中的日志- org.springframework.Security.Access.event.loggerlistener-安全授权失败,原因是:org.springframework.Security.Access.accessdeniedexception:访问被拒绝;通过身份验证的主体:org.springframework.security.authentication.ano

  • 问题内容: 我想设置我的网站,以便如果用户点击该页面并且他们已经登录,它将把他们重定向到主页。如果未登录,它将正常显示。由于登录代码内置在Django中,我该怎么做? 问题答案: 我假设你当前正在使用内置的登录视图, 或你网址中的类似内容。 你可以编写包含默认视图的登录视图。它将检查用户是否已经登录,如果已经登录则重定向,否则使用默认视图。 就像是: 当然可以相应地更改你的网址:

  • 我现在一直在努力使用我的登录页面来让组件呈现Loggedin组件。我的前端是Reactjs,后端是NodeJS。我对nodejs、expression和react都是新手。 在loginform组件上,我使用fetch进行了一次post,它将用户名和密码传递给后端的相应endpoint。没问题。在后端,它读取我存储用户(不使用任何数据库)的jsonfile来查找匹配项,如果用户名和密码都匹配,则它

  • 问题内容: 我正在做一个简单的论坛,由一系列论坛组成,每个论坛分别代表首页,主题,postitit,登录名和用户列表页面。在某些页面上,当用户未登录时会出现一个链接。 我想要实现的是在登录后触发重定向(在RequestDispatcher上使用forward()),以便浏览器返回到用户在单击登录链接之前所在的页面。为此,我看到了两种解决方案。 第一种解决方案是使用带有登录按钮的HTML 和一个不可

  • 我有一个文件,带有一个,具有和字段,在上,它用

  • 我在Laravel框架中的HomeController.php中有一段代码,但是我无法访问它重定向到登录页面的索引/主页。我犯了什么大错?