无法使用表单身份验证进行身份验证

时间:2020-05-29 16:03:18

标签: spring-boot spring-security

我无法弄清楚为什么我无法进行身份验证。在查看了跟踪之后,我认为该会话没有被创建或被清除,或者具有某种性质。我的Admin Controller登录后方法中有一段代码,如果不加注释,则验证有效,但是我不想手动执行此操作,因为Spring应该为我处理。任何帮助将不胜感激,如果我可以提供其他源代码帮助,请告诉我。

详细信息:

我正在使用 Spring Boot Spring Security Thymleaf ,并通过 Localhost 运行它。

每次我在/ admin / **上查看页面时,都会出现登录页面,并且需要提供凭据。输入凭据后,登录页面将处理并显示/ admin / index(根据控制器),但是当我尝试导航到另一个页面(例如:/ admin / orgs)时,将再次出现登录屏幕。除了显而易见的以外,我知道用户未通过身份验证,因为我检查用户是否在/ admin / index上通过了身份验证。

项目结构

+ src
    + main
        + java
            - org.neric (package)
                - SecurityConfig
                - AdminController
                - AppController
                - Application
                - WebConfig
        + resources
            + templates
                - index.html 
                + admin
                    - index.html
                    - login.html
                    - orgs.html
            + static
                + css
                + js
                + img

跟踪(application.properties trace = true)

2020-05-29 10:47:32.511 DEBUG 15316 --- [nio-8080-exec-1] o.a.tomcat.util.net.SocketWrapperBase    : Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@77ed1e40:org.apache.tomcat.util.net.NioChannel@78cb69e6:java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:8080 remote=/0:0:0:0:0:0:0:1:50574]], Read from buffer: [0]
2020-05-29 10:47:32.511 DEBUG 15316 --- [nio-8080-exec-1] org.apache.tomcat.util.net.NioEndpoint   : Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@77ed1e40:org.apache.tomcat.util.net.NioChannel@78cb69e6:java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:8080 remote=/0:0:0:0:0:0:0:1:50574]], Read direct from socket: [872]
2020-05-29 10:47:32.512 DEBUG 15316 --- [nio-8080-exec-1] o.a.t.util.http.Rfc6265CookieProcessor   : Cookies: Parsing b[]: sidenav-state=pinned; JSESSIONID=408BA31320628AA0E4E3E3D9FBEDC8DD
2020-05-29 10:47:32.512 DEBUG 15316 --- [nio-8080-exec-1] o.a.catalina.connector.CoyoteAdapter     :  Requested cookie session id is 408BA31320628AA0E4E3E3D9FBEDC8DD
2020-05-29 10:47:32.512 DEBUG 15316 --- [nio-8080-exec-1] o.a.c.authenticator.AuthenticatorBase    : Security checking request POST /admin/login
2020-05-29 10:47:32.512 DEBUG 15316 --- [nio-8080-exec-1] org.apache.catalina.realm.RealmBase      :   No applicable constraints defined
2020-05-29 10:47:32.512 DEBUG 15316 --- [nio-8080-exec-1] o.a.c.authenticator.AuthenticatorBase    :  Not subject to any constraint
2020-05-29 10:47:32.512 DEBUG 15316 --- [nio-8080-exec-1] o.apache.catalina.core.StandardWrapper   :   Returning non-STM instance
2020-05-29 10:47:32.513 DEBUG 15316 --- [nio-8080-exec-1] org.apache.tomcat.util.http.Parameters   : Set encoding to UTF-8
2020-05-29 10:47:32.513 DEBUG 15316 --- [nio-8080-exec-1] org.apache.tomcat.util.http.Parameters   : Start processing with input [%24%7B_csrf.parameterName%7D=%24%7B_csrf.token%7D&email=admin%40neric.org&password=123456]
2020-05-29 10:47:32.513 TRACE 15316 --- [nio-8080-exec-1] o.s.b.w.s.f.OrderedRequestContextFilter  : Bound request context to thread: org.apache.catalina.connector.RequestFacade@2b59dd1c
2020-05-29 10:47:32.513 DEBUG 15316 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /admin/login at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-05-29 10:47:32.513 DEBUG 15316 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /admin/login at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-05-29 10:47:32.513 DEBUG 15316 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2020-05-29 10:47:32.513 DEBUG 15316 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
2020-05-29 10:47:32.513 DEBUG 15316 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /admin/login at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2020-05-29 10:47:32.513 DEBUG 15316 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /admin/login at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
2020-05-29 10:47:32.513 DEBUG 15316 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/admin/logout', GET]
2020-05-29 10:47:32.513 DEBUG 15316 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'POST /admin/login' doesn't match 'GET /admin/logout'
2020-05-29 10:47:32.513 DEBUG 15316 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/admin/logout', POST]
2020-05-29 10:47:32.513 DEBUG 15316 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/admin/login'; against '/admin/logout'
2020-05-29 10:47:32.513 DEBUG 15316 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/admin/logout', PUT]
2020-05-29 10:47:32.513 DEBUG 15316 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'POST /admin/login' doesn't match 'PUT /admin/logout'
2020-05-29 10:47:32.513 DEBUG 15316 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/admin/logout', DELETE]
2020-05-29 10:47:32.513 DEBUG 15316 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'POST /admin/login' doesn't match 'DELETE /admin/logout'
2020-05-29 10:47:32.514 DEBUG 15316 --- [nio-8080-exec-1] o.s.s.web.util.matcher.OrRequestMatcher  : No matches found
2020-05-29 10:47:32.514 DEBUG 15316 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /admin/login at position 5 of 11 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2020-05-29 10:47:32.514 DEBUG 15316 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/admin/login'; against 'admin/login'
2020-05-29 10:47:32.514 DEBUG 15316 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /admin/login at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2020-05-29 10:47:32.514 DEBUG 15316 --- [nio-8080-exec-1] o.s.s.w.s.HttpSessionRequestCache        : saved request doesn't match
2020-05-29 10:47:32.514 DEBUG 15316 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /admin/login at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2020-05-29 10:47:32.514 DEBUG 15316 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /admin/login at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2020-05-29 10:47:32.514 DEBUG 15316 --- [nio-8080-exec-1] o.s.s.w.a.AnonymousAuthenticationFilter  : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@3bcd7783: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
2020-05-29 10:47:32.514 DEBUG 15316 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /admin/login at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
2020-05-29 10:47:32.514 DEBUG 15316 --- [nio-8080-exec-1] o.s.s.w.session.SessionManagementFilter  : Requested session ID 408BA31320628AA0E4E3E3D9FBEDC8DD is invalid.
2020-05-29 10:47:32.514 DEBUG 15316 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /admin/login at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2020-05-29 10:47:32.514 DEBUG 15316 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /admin/login at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2020-05-29 10:47:32.514 DEBUG 15316 --- [nio-8080-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /admin/login; Attributes: [permitAll]
2020-05-29 10:47:32.514 DEBUG 15316 --- [nio-8080-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@3bcd7783: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
2020-05-29 10:47:32.514 DEBUG 15316 --- [nio-8080-exec-1] o.s.s.access.vote.AffirmativeBased       : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@2cf46161, returned: 1
2020-05-29 10:47:32.514 DEBUG 15316 --- [nio-8080-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Authorization successful
2020-05-29 10:47:32.514 DEBUG 15316 --- [nio-8080-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor    : RunAsManager did not change Authentication object
2020-05-29 10:47:32.514 DEBUG 15316 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : /admin/login reached end of additional filter chain; proceeding with original chain
2020-05-29 10:47:32.514 TRACE 15316 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : POST "/admin/login", parameters={masked}, headers={masked} in DispatcherServlet 'dispatcherServlet'
2020-05-29 10:47:32.515 TRACE 15316 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'adminController'
2020-05-29 10:47:32.515 TRACE 15316 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public java.lang.String org.neric.AdminController.processForm(javax.servlet.http.HttpServletRequest,org.neric.bean.Login)
2020-05-29 10:47:32.515 TRACE 15316 --- [nio-8080-exec-1] o.s.web.cors.DefaultCorsProcessor        : Skip: request is from same origin
2020-05-29 10:47:32.516 TRACE 15316 --- [nio-8080-exec-1] .w.s.m.m.a.ServletInvocableHandlerMethod : Arguments: [SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.context.HttpSessionSecurityContextRepository$Servlet3SaveToSessionRequestWrapper@377af4f5], Login{email='admin@neric.org', password='123456'}]
Login{email='admin@neric.org', password='123456'}
2020-05-29 10:47:32.516 TRACE 15316 --- [nio-8080-exec-1] o.s.w.s.v.InternalResourceViewResolver   : View with key [admin/index] served from cache
2020-05-29 10:47:32.516 DEBUG 15316 --- [nio-8080-exec-1] o.s.w.s.v.ContentNegotiatingViewResolver : Selected 'text/html' given [text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, application/signed-exchange;v=b3;q=0.9, */*;q=0.8]
2020-05-29 10:47:32.516 TRACE 15316 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Rendering view [org.thymeleaf.spring5.view.ThymeleafView@6137df47] 
2020-05-29 10:47:32.516 TRACE 15316 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'requestDataValueProcessor'
2020-05-29 10:47:32.520 TRACE 15316 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'webSecurityExpressionHandler'
2020-05-29 10:47:32.520 TRACE 15316 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'webSecurityExpressionHandler'
2020-05-29 10:47:32.522 DEBUG 15316 --- [nio-8080-exec-1] o.s.s.w.header.writers.HstsHeaderWriter  : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@5b0bf2c9
2020-05-29 10:47:32.522 DEBUG 15316 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2020-05-29 10:47:32.523 DEBUG 15316 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed 200 OK, headers={masked}
2020-05-29 10:47:32.523 DEBUG 15316 --- [nio-8080-exec-1] o.s.s.w.a.ExceptionTranslationFilter     : Chain processed normally
2020-05-29 10:47:32.523 DEBUG 15316 --- [nio-8080-exec-1] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2020-05-29 10:47:32.523 TRACE 15316 --- [nio-8080-exec-1] o.s.b.w.s.f.OrderedRequestContextFilter  : Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@2b59dd1c
2020-05-29 10:47:32.523 DEBUG 15316 --- [nio-8080-exec-1] o.a.tomcat.util.net.SocketWrapperBase    : Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@77ed1e40:org.apache.tomcat.util.net.NioChannel@78cb69e6:java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:8080 remote=/0:0:0:0:0:0:0:1:50574]], Read from buffer: [0]
2020-05-29 10:47:32.523 DEBUG 15316 --- [nio-8080-exec-1] org.apache.tomcat.util.net.NioEndpoint   : Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@77ed1e40:org.apache.tomcat.util.net.NioChannel@78cb69e6:java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:8080 remote=/0:0:0:0:0:0:0:1:50574]], Read direct from socket: [0]

POM

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>

    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        <version>3.0.4.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
<dependencies>

应用

@EnableScheduling
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

SecurityConfig

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

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

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("user@neric.org")
                .password(passwordEncoder().encode("123456"))
                .roles("USER")
            .and()
                .withUser("admin@neric.org")
                    .password(passwordEncoder().encode("123456"))
                    .roles("ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
       http
        .authorizeRequests()
            .antMatchers("/admin/**").hasRole("ADMIN")
        .and()
            .formLogin()
                .loginPage("/admin/login")
                    .usernameParameter("email")
                    .passwordParameter("password")
                .loginProcessingUrl("admin/login") //dont change, it's not the same as the line above.... /smh...
                .failureUrl("/404")
            .permitAll()
        .and()
            .logout()
                .logoutUrl("/admin/logout")
                .invalidateHttpSession(true)
            .permitAll()
        .and()
            .csrf()
                .disable()
        //.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
       ;
    }
}

WebConfig

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/webjars/**", "/img/**", "/css/**", "/js/**")
            .addResourceLocations("classpath:/META-INF/resources/webjars/", "classpath:/static/img/", "classpath:/static/css/", "classpath:/static/js/")
        ;
    }

}

AdminController

@Controller
public class AdminController {

    @GetMapping("/admin/logout")
    public String logout(Login login) {
        return "admin/login";
    }

    @PostMapping("/admin/logout")
    public String logoutPost(Login login) {
        return "admin/login";
    }

    @GetMapping("/admin/login")
    public String login(Login login) {
        return "admin/login";
    }

    @PostMapping("/admin/login")
    public String processForm(HttpServletRequest req, Login login)  {
        System.out.println(login);

        /* If I uncomment this, I can force authentication. Though, I shouldn't have to
        UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(login.getEmail(), login.getPassword());
        Authentication auth = authManager.authenticate(authReq);

        SecurityContext sc = SecurityContextHolder.getContext();
        sc.setAuthentication(auth);
        HttpSession session = req.getSession(true);
        session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, sc);*/

        return "admin/index";
    }

    @GetMapping("/admin")
    public String showAdmin() {
        return "admin/index";
    }

    @GetMapping("/admin/orgs")
    public String showOrgs(Organization organization) {
        return "admin/orgs";
    }
}

/ admin / login (/resources/templates/admin/login.html)

<!doctype html>
<html xmlns:th="http://www.thymeleaf.org"
  xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
  lang="en">

<head>
    <link rel="stylesheet" th:href="@{/css/bootstrap.min.css}" />
    <link rel="stylesheet" th:href="@{/css/all.min.css}" />
    <link rel="stylesheet" th:href="@{/css/login.css}" />

</head>
<body>
    <div class="app-container app-theme-white body-tabs-shadow">
        <div class="app-container">
            <div class="h-100 bg-animation">
                <div class="d-flex h-100 justify-content-center align-items-center">
                    <div class="mx-auto app-login-box col-md-8">
                        <div class="app-logo mx-auto mb-3"></div>

                        <form th:action="@{/admin/login}" th:object="${login}" method="post" class="needs-validation" novalidate>
                            <div class="modal-dialog w-100 mx-auto">
                                <div class="modal-content">
                                    <div class="modal-body">
                                        <div class="h5 modal-title text-center">
                                            <h4 class="mt-2">
                                                <div>Welcome back,</div>
                                                <span>Please sign in to your account below.</span>
                                            </h4>
                                        </div>

                                            <div class="form-row">
                                                <div class="col-md-12">
                                                    <div class="position-relative form-group">
                                                        <input name="email" id="exampleEmail" placeholder="Email here..." type="email" class="form-control" th:field="*{email}" required>
                                                    </div>
                                                </div>
                                                <div class="col-md-12">
                                                    <div class="position-relative form-group">
                                                        <input name="password" id="examplePassword" placeholder="Password here..." type="password" class="form-control" th:field="*{password}" required>
                                                    </div>
                                                </div>
                                            </div>
                                    </div>
                                    <div class="modal-footer clearfix">
                                        <div class="float-left">
                                            <a href="javascript:void(0);" class="btn-lg btn btn-link">Recover Password</a> <!--TODO-->
                                        </div>
                                        <div class="float-right">
                                            <button class="btn btn-primary btn-lg" type="submit">Login</button>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </form>
                        <div class="text-center text-black opacity-8 mt-3" th:text="'Copyright © Capital Region BOCES ' + ${#dates.year(#dates.createNow())}"></div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script th:src="@{/js/jquery.min.js}"></script>
    <script th:src="@{/js/bootstrap.bundle.min.js}"></script>
    <script>
        (function() {
            'use strict';

            window.addEventListener('load', function() {
                // Fetch all the forms we want to apply custom Bootstrap validation styles to
                var forms = document.getElementsByClassName('needs-validation');

                // Loop over them and prevent submission
                var validation = Array.prototype.filter.call(forms, function(form) {
                    form.addEventListener('submit', function(event) {
                        if (form.checkValidity() === false) {
                            event.preventDefault();
                            event.stopPropagation();
                        }
                        form.classList.add('was-validated');
                    }, false);
                });
            }, false);
        })();
    </script>

</body>

管理员/索引(/resources/templates/admin/index.html)

重要部分

    <div sec:authorize="isAuthenticated()">
        Authenticated
    </div>
    <div sec:authorize="!isAuthenticated()">
        Not authenticated
    </div>

整页

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security" lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <!-- Favicon -->
    <link rel="icon" href="../../assets/img/brand/favicon.png" type="image/png">
    <!-- Fonts -->
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700">
    <!-- Icons -->
    <link rel="stylesheet" th:href="@{/css/nucleo.css}" />
    <link rel="stylesheet" th:href="@{/css/all.min.css}" />
    <!-- Argon CSS -->
    <link rel="stylesheet" th:href="@{/css/argon.css}" />
    <!--<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">-->
</head>

<body class="docs">
<header class="navbar navbar-horizontal navbar-expand navbar-dark flex-row align-items-md-center ct-navbar">
    <a class="navbar-brand mr-0 mr-md-2" th:href="@{/admin/}" aria-label="Admin">
        <img src="https://www.capitalregionboces.org/wp-content/themes/twentyseventeen-child/images/crb-logo-header.svg">
        <sup>Admin</sup>
    </a>
</header>
<div class="container-fluid">
    <div class="row flex-xl-nowrap">
        <div class="col-12 col-md-3 col-xl-2 ct-sidebar">
            <nav class="collapse ct-links" id="ct-docs-nav">
                <!-- Show links for all groups -->
                <div class="ct-toc-item active">
                    <a class="ct-toc-link" href="../../docs/getting-started/overview.html">Manage</a>
                    <ul class="nav ct-sidenav">
                        <li class="active ct-sidenav-active">
                            <a th:href="@{/admin/orgs}">Organizations</a>
                        </li>
                        <li>
                            <a th:href="@{/admin/buildings}">Buildings</a>
                        </li>
                        <li>
                            <a th:href="@{/admin/roles}">Roles</a>
                        </li>
                    </ul>
                </div>
                <!-- Show links for all groups -->
                <div class="ct-toc-item active">
                    <a class="ct-toc-link" href="../../docs/foundation/colors.html">Reports</a>
                    <ul class="nav ct-sidenav">
                        <li>
                            <a th:href="@{/admin/reports/dailyUsage}">Daily Usage</a>
                        </li>
                    </ul>
                </div>

            </nav>
        </div>

        <!-- Main Content: Side Bar -->
        <div class="d-none d-xl-block col-xl-2 ct-toc">
            <ul class="section-nav">
                <li class="toc-entry toc-h3"><a th:href="@{/admin/orgs/add}">Add Organization</a></li>
            </ul>
        </div>

        <main class="col-12 col-md-8 col-xl-7 py-md-3 pl-md-5 ct-content" role="main">
            <!-- Main Content: Header -->
            <div class="ct-page-title">
                <h1 class="ct-title" id="content">Index</h1>
                <div class="avatar-group mt-3"></div>
            </div>
            <!--<p class="ct-lead">A list of all the organizations.</p>-->

            <hr>

            <!-- Main Content -->

            <div sec:authorize="isAuthenticated()">
                Authenticated
            </div>

            <div sec:authorize="!isAuthenticated()">
                Not authenticated
            </div>

            <!-- End Main Content -->

        </main>
    </div>
</div>
<!-- Core -->
<script th:src="@{/js/jquery.min.js}"></script>
<script th:src="@{/js/bootstrap.bundle.min.js}"></script>
<script th:src="@{/js/js.cookie.js}"></script>
<script th:src="@{/js/jquery.scrollbar.min.js}"></script>
<script th:src="@{/js/jquery-scrollLock.min.js}"></script>
<!-- Docs JS -->
<script th:src="@{/js/anchor.min.js}"></script>
<script th:src="@{/js/clipboard.min.js}"></script>
<script th:src="@{/js/holder.min.js}"></script>
<script th:src="@{/js/prism.js}"></script>
<!-- Argon JS -->
<script th:src="@{/js/argon.min.js}"></script>
</body>

</html>

1 个答案:

答案 0 :(得分:2)

问题出在您的安全配置中。

您正在保护一切。见下文。

http
    .authorizeRequests()
        .antMatchers("/admin/**").hasRole("ADMIN")

因此,它将使您一次又一次发送登录页面。因为它没有成功通过安全筛选器。

我建议将您的控制器映射更改为@GetMapping("/login"),并通过添加以下配置更改来允许所有人使用它

 @Override
protected void configure(HttpSecurity http) throws Exception {
   http
    .authorizeRequests().antMatchers("/login").permitAll()
        .antMatchers("/admin/**").hasRole("ADMIN")
    .and()
        .formLogin().loginPage("/login") // cutom login page. 
        .usernameParameter("email")
        .passwordParameter("password")
        .loginProcessingUrl("/login")  // this should be public too(which we did) as user's request would reach here then authentication will happen. 
        .defaultSuccessUrl("/loginSuccess") // this has to be done since you have two different role so we need to identify whether user role or admin role and based on that redirection should happen.
    .and()
        .logout()
            .logoutUrl("/logout") // logout should be common for both roles so don't add /admin/logout  
             .invalidateHttpSession(true)
        .permitAll()
    .and()
        .csrf()
            .disable()
    //.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
   ;
}

这是控制器:

@Controller 
public class AdminController {
@GetMapping("/login")
public String login() {
    return "admin/login";
}
@GetMapping("/loginSuccess")
public String showAdmin(@AuthenticationPrincipal User userDetails) {
    // check the role if user then redirect to user page, if admin then redirect to admin page. 
    List<GrantedAuthority> authorties = userDetails.getAuthorities().stream().collect(Collectors.toList());

    boolean isAdmin=false;
    if(authorties.stream().anyMatch(p->p.getAuthority().equals("ROLE_ADMIN"))) {
        return "admin/index";
    } else {
        return "user/index";
    }
}

}

结帐工作代码here