简体   繁体   中英

Spring security only shows header of login page

I've been wrestling with this one for a while.

I have a web application that I'm trying to put Spring Security into. I have successfully made it so that whenever a user attempts to access pages they are not authorized to, it redirects them to the login page. The problem is that the login page is not showing - just the header for the login page (and it isn't stylized). I'm very confused by this, because all other pages are displaying fine.

This is the example I'm working from I'm pretty much trying to follow it to the letter and have even downloaded it, but I'm not able to quite see what I am doing differently in my own project.

The only big difference I see is that I'm using Gradle and this guy is using Maven.

Here is my build.gradle:

 buildscript { repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.7.RELEASE") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'idea' apply plugin: 'org.springframework.boot' jar { baseName = 'gs-spring-boot' baseName = 'gs-handling-form-submission' baseName = 'gs-serving-mobile-web-content' baseName = 'gs-accessing-data-mongodb' baseName = 'gs-rest-service-cors' baseName = 'gs-securing-web' version = '0.1.0' } repositories { mavenCentral() } sourceCompatibility = 1.8 targetCompatibility = 1.8 dependencies { compile("org.springframework.boot:spring-boot-starter-web") { exclude module: "spring-boot-starter-tomcat" } compile("org.springframework.boot:spring-boot-starter-jetty") testCompile("org.springframework.boot:spring-boot-starter-test") compile("org.springframework.boot:spring-boot-starter-actuator") testCompile 'junit:junit:4.12' compile("org.springframework.boot:spring-boot-starter-data-mongodb") compile group: 'joda-time', name: 'joda-time', version: '2.8.1' compile("org.springframework.boot:spring-boot-starter-web:1.3.0.RELEASE") compile 'org.slf4j:slf4j-api:1.7.13' compile("org.springframework.boot:spring-boot-starter-web") compile("org.springframework.boot:spring-boot-parent:1.5.3.RELEASE") compile("org.springframework.boot:spring-boot-starter-thymeleaf") compile("org.springframework.boot:spring-boot-starter-data-mongodb") compile("org.springframework.boot:spring-boot-starter-mobile") compile("org.springframework.boot:spring-boot-starter-data-jpa") compile("com.h2database:h2") compile("net.sourceforge.nekohtml:nekohtml:1.9.21") compile("org.springframework.boot:spring-boot-starter-data-mongodb:1.2.0.RELEASE") compile("org.springframework.boot.spring-boot-starter-remote-shell:1.2.0.RELEASE") compile("org.thymeleaf.extras:thymeleaf-extras-springsecurity4") compile("org.springframework.boot:spring-boot-devtools:true") testCompile("org.springframework.security:spring-security-test") compile("org.springframework.boot:spring-boot-starter-security") }

Here is my Controller:

 @Controller public class WebController { //implements ErrorController{ private static final String PATH = "/error"; private BlogPostRepo blogPostRepo; @Autowired public WebController(BlogPostRepo blogPostRepo) { this.blogPostRepo = blogPostRepo; } @RequestMapping("/index") public String displayBlogPosts(Model model){ model.addAttribute("blogPosts", blogPostRepo.findAll()); return "index"; } @RequestMapping("/login") public String login(){ return "/login"; } @GetMapping("/403") public String error403() { return "/error/403"; } }

Here is SpringSecurityConfig.java :

 package com.stereoscopics.app.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.web.access.AccessDeniedHandler; @Configuration // http://docs.spring.io/spring-boot/docs/current/reference/html/howto-security.html // Switch off the Spring Boot security configuration //@EnableWebSecurity public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private AccessDeniedHandler accessDeniedHandler; // roles admin allow to access /admin/** // roles user allow to access /user/** // custom 403 access denied handler @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/", "/index", "/submitAnArticle").permitAll() .antMatchers("/admin/**").hasAnyRole("ADMIN") .antMatchers("/user/**").hasAnyRole("USER") .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .permitAll() .and() .logout() .permitAll() .and() .exceptionHandling().accessDeniedHandler(accessDeniedHandler); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("user").password("password").roles("USER") .and() .withUser("admin").password("password").roles("ADMIN"); } }

Here is my AccessDeniedHandler.java:

 package com.stereoscopics.app.error; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; // handle 403 page @Component public class MyAccessDeniedHandler implements AccessDeniedHandler { private static Logger logger = LoggerFactory.getLogger(MyAccessDeniedHandler.class); @Override public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null) { logger.info("User '" + auth.getName() + "' attempted to access the protected URL: " + httpServletRequest.getRequestURI()); } httpServletResponse.sendRedirect(httpServletRequest.getContextPath() + "/403"); } }

Here is my login:

 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" > <head> <title>Spring Security Example </title> <div th:replace="fragments/header :: header-css"/> </head> <body> <div th:replace="fragments/header :: header"/> <div class="container"> <div class="row" style="margin-top:20px"> <div class="col-xs-12 col-sm-8 col-md-6 col-sm-offset-2 col-md-offset-3"> <form th:action="@{/login}" method="post"> <fieldset> <h1>Please Sign In</h1> <div th:if="${param.error}"> <div class="alert alert-danger"> Invalid username and password. </div> </div> <div th:if="${param.logout}"> <div class="alert alert-info"> You have been logged out. </div> </div> <div class="form-group"> <input type="text" name="username" id="username" class="form-control input-lg" placeholder="UserName" required="true" autofocus="true"/> </div> <div class="form-group"> <input type="password" name="password" id="password" class="form-control input-lg" placeholder="Password" required="true"/> </div> <div class="row"> <div class="col-xs-6 col-sm-6 col-md-6"> <input type="submit" class="btn btn-lg btn-primary btn-block" value="Sign In"/> </div> <div class="col-xs-6 col-sm-6 col-md-6"> </div> </div> </fieldset> </form> </div> </div> </div> <div th:replace="fragments/footer :: footer"/> </body> </html>

Here is my header:

 <html xmlns:th="http://www.thymeleaf.org"> <head> <div th:fragment="header-css"> <!-- this is header-css --> <link rel="stylesheet" type="text/css" href="webjars/bootstrap/3.3.7/css/bootstrap.min.css" /> <link rel="stylesheet" th:href="@{/css/main.css}" href="../../css/main.css" /> </div> </head> <body> <div th:fragment="header"> <!-- this is header --> <nav class="navbar navbar-inverse"> <div class="container"> <div class="navbar-header"> <a class="navbar-brand" th:href="@{/}">Spring Boot</a> </div> <div id="navbar" class="collapse navbar-collapse"> <ul class="nav navbar-nav"> <li class="active"><a th:href="@{/}">Home</a></li> </ul> </div> </div> </nav> </div> </body> </html>

Here's what I've tried:

Checking the file paths - the header and footer are in \\resources\\templates\\fragments and the other files are in resources\\templates

Google (cannot find anything)

Double-Checking Dependencies

Downloading the example and cross checking

I am very, very confused. Please help.

It's hard to debug without a runnable example (a git repository that I could clone would be nice), but one thing I see is that your security config requires authentication to access the stylesheets.

Add

.antMatchers("/webjars/**").permitAll()
.antMatchers("/css/**").permitAll()

to your security config and the stylesheets should load.

Additionally you should probably use an absolute path to the stylesheets in your header since ../../css/main.css might not work for all your URLs.

A good way to debug these things is to use the web console in your browser and look at the network requests and see whether or not all assets are loaded correctly.

Are you sure that its your login page that isn't showing properly? I believe that you could be redirecting improperly authenticated requests to the wrong page. When you handle requests that are denied in your MyAccessDeniedHandler class you execute the following:

httpServletResponse.sendRedirect(httpServletRequest.getContextPath() + "/403");

This is in turn handled by the WebController class with the following code:

@GetMapping("/403")
public String error403() {
    return "/error/403";
}

So, it seems as if you are not actually rendering the login page when you handle 403's.

I'm not familiar with thyme leaf, but my guess is that you have not defined the error/403 file, and that a header is rendered even if the html file is not found when rendering pages.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM