Spring 开机不显示网页内容
Spring Boot not displaying web contents
我有一个 Spring 引导应用程序用作安全 REST API 后端。
我想要一些带有相关文档的静态页面 API(例如,我想使用 Wiki)
据我所知,我无法让它显示静态内容:例如我尝试使用 greeting example and invoking http://localhost:8080/greeting 它会显示“greeting”(不提供 greeting.html 页面)
我怀疑问题与 Spring 安全中的某些过滤器有关。
这就是调用的过滤器链
o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'
o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 19 ms
o.s.security.web.FilterChainProxy : /greeting at position 1 of 7 in additional filter chain; firing Filter: 'HeaderWriterFilter'
o.s.security.web.FilterChainProxy : /greeting at position 2 of 7 in additional filter chain; firing Filter: 'StatelessLoginFilter'
o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/greeting'; against '/api/login'
o.s.security.web.FilterChainProxy : /greeting at position 3 of 7 in additional filter chain; firing Filter: 'StatelessAuthenticationFilter'
o.s.security.web.FilterChainProxy : /greeting at position 4 of 7 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
o.s.security.web.FilterChainProxy : /greeting at position 5 of 7 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
o.s.s.w.a.AnonymousAuthenticationFilter : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: 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'
o.s.security.web.FilterChainProxy : /greeting at position 6 of 7 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
o.s.security.web.FilterChainProxy : /greeting at position 7 of 7 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/greeting'; against '/'
o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/greeting'; against '/documentation'
o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/greeting'; against '/greeting'
o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /greeting; Attributes: [permitAll]
o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: 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
o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@58e65a6f, returned: 1
o.s.s.w.a.i.FilterSecurityInterceptor : Authorization successful
o.s.s.w.a.i.FilterSecurityInterceptor : RunAsManager did not change Authentication object
o.s.security.web.FilterChainProxy : /greeting reached end of additional filter chain; proceeding with original chain
o.s.s.w.a.ExceptionTranslationFilter : Chain processed normally
我把greeting.html文件放在src/main/webapp/WEB-INF/templates和src/main/resources/templates里,我试着在application.properties里指定
# For the standard MVC JSTL view resolver
spring.view.prefix=/WEB-INF/templates/
spring.view.suffix=.html
我尝试了这些 Whosebug 中提出的解决方案:“Spring Boot not serving static content" and "spring boot not launching static web content”但没有任何改变......
最后这是 WebSecurityConfigurerAdapter:
public class StatelessAuthenticationSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private TokenAuthenticationService tokenAuthenticationService;
@Autowired
private LDAPAuthenticationService ldapAuthenticationService;
@Value("${ldap.useLdapForAuthentication}")
private String useLdapForAuthentication;
public StatelessAuthenticationSecurityConfig() {
super(true);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling().and()
.anonymous().and()
.servletApi().and()
.headers().cacheControl().and()
.authorizeRequests()
//allow anonymous resource requests
.antMatchers("/").permitAll()
.antMatchers("/documentation").permitAll()
.antMatchers("/greeting").permitAll()
.antMatchers("/favicon.ico").permitAll()
.antMatchers("/resources/**").permitAll()
//allow anonymous POSTs to login
.antMatchers(HttpMethod.OPTIONS, "/api/login").permitAll()
.antMatchers(HttpMethod.POST, "/api/login").permitAll()
.antMatchers(HttpMethod.OPTIONS, "/api/**").permitAll()
.antMatchers(HttpMethod.POST, "/api/**").hasAnyRole("ADMIN", "USER")
.antMatchers(HttpMethod.GET, "/api/**").hasAnyRole("ADMIN", "USER") //e compagnia cantando
//defined Admin only API area
.antMatchers("/admin/**").hasRole("ADMIN")
//all other request need to be authenticated
.anyRequest().hasRole("USER")
.and()
// custom JSON based authentication by POST of {"username":"<name>","password":"<password>"} which sets the token header upon authentication
.addFilterBefore(new StatelessLoginFilter("/api/login", tokenAuthenticationService, userDetailsService, ldapAuthenticationService, authenticationManager(), useLdapForAuthentication), UsernamePasswordAuthenticationFilter.class)
// custom Token based authentication based on the header previously given to the client
.addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService), UsernamePasswordAuthenticationFilter.class);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
@Override
protected UserDetailsService userDetailsService() {
return userDetailsService;
}
}
.antMatchers("/resources/**").permitAll() - 甚至应该允许访问 resources/templates
我真的不明白为什么它不呈现网页内容
拜托,你能给我一些提示吗?
EDIT1
控制器:
@RestController
public class GreetingController {
@RequestMapping("/greeting")
public String greeting(@RequestParam(value="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name);
return "greeting";
}
}
根据 Spring 指南:Building a RESTful Web Service
A key difference between a traditional MVC controller and the RESTful
web service controller above is the way that the HTTP response body is
created. Rather than relying on a view technology to perform
server-side rendering of the greeting data to HTML, this RESTful web
service controller simply populates and returns a Greeting object. The
object data will be written directly to the HTTP response as JSON.
因此在您的情况下 return "greetings" 在 JSON 中。如果你想让它return页面greeting.html,你应该使用正常的@Controller
.
我有一个 Spring 引导应用程序用作安全 REST API 后端。 我想要一些带有相关文档的静态页面 API(例如,我想使用 Wiki)
据我所知,我无法让它显示静态内容:例如我尝试使用 greeting example and invoking http://localhost:8080/greeting 它会显示“greeting”(不提供 greeting.html 页面)
我怀疑问题与 Spring 安全中的某些过滤器有关。
这就是调用的过滤器链
o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'
o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 19 ms
o.s.security.web.FilterChainProxy : /greeting at position 1 of 7 in additional filter chain; firing Filter: 'HeaderWriterFilter'
o.s.security.web.FilterChainProxy : /greeting at position 2 of 7 in additional filter chain; firing Filter: 'StatelessLoginFilter'
o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/greeting'; against '/api/login'
o.s.security.web.FilterChainProxy : /greeting at position 3 of 7 in additional filter chain; firing Filter: 'StatelessAuthenticationFilter'
o.s.security.web.FilterChainProxy : /greeting at position 4 of 7 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
o.s.security.web.FilterChainProxy : /greeting at position 5 of 7 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
o.s.s.w.a.AnonymousAuthenticationFilter : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: 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'
o.s.security.web.FilterChainProxy : /greeting at position 6 of 7 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
o.s.security.web.FilterChainProxy : /greeting at position 7 of 7 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/greeting'; against '/'
o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/greeting'; against '/documentation'
o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/greeting'; against '/greeting'
o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /greeting; Attributes: [permitAll]
o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: 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
o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@58e65a6f, returned: 1
o.s.s.w.a.i.FilterSecurityInterceptor : Authorization successful
o.s.s.w.a.i.FilterSecurityInterceptor : RunAsManager did not change Authentication object
o.s.security.web.FilterChainProxy : /greeting reached end of additional filter chain; proceeding with original chain
o.s.s.w.a.ExceptionTranslationFilter : Chain processed normally
我把greeting.html文件放在src/main/webapp/WEB-INF/templates和src/main/resources/templates里,我试着在application.properties里指定
# For the standard MVC JSTL view resolver
spring.view.prefix=/WEB-INF/templates/
spring.view.suffix=.html
我尝试了这些 Whosebug 中提出的解决方案:“Spring Boot not serving static content" and "spring boot not launching static web content”但没有任何改变......
最后这是 WebSecurityConfigurerAdapter:
public class StatelessAuthenticationSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private TokenAuthenticationService tokenAuthenticationService;
@Autowired
private LDAPAuthenticationService ldapAuthenticationService;
@Value("${ldap.useLdapForAuthentication}")
private String useLdapForAuthentication;
public StatelessAuthenticationSecurityConfig() {
super(true);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling().and()
.anonymous().and()
.servletApi().and()
.headers().cacheControl().and()
.authorizeRequests()
//allow anonymous resource requests
.antMatchers("/").permitAll()
.antMatchers("/documentation").permitAll()
.antMatchers("/greeting").permitAll()
.antMatchers("/favicon.ico").permitAll()
.antMatchers("/resources/**").permitAll()
//allow anonymous POSTs to login
.antMatchers(HttpMethod.OPTIONS, "/api/login").permitAll()
.antMatchers(HttpMethod.POST, "/api/login").permitAll()
.antMatchers(HttpMethod.OPTIONS, "/api/**").permitAll()
.antMatchers(HttpMethod.POST, "/api/**").hasAnyRole("ADMIN", "USER")
.antMatchers(HttpMethod.GET, "/api/**").hasAnyRole("ADMIN", "USER") //e compagnia cantando
//defined Admin only API area
.antMatchers("/admin/**").hasRole("ADMIN")
//all other request need to be authenticated
.anyRequest().hasRole("USER")
.and()
// custom JSON based authentication by POST of {"username":"<name>","password":"<password>"} which sets the token header upon authentication
.addFilterBefore(new StatelessLoginFilter("/api/login", tokenAuthenticationService, userDetailsService, ldapAuthenticationService, authenticationManager(), useLdapForAuthentication), UsernamePasswordAuthenticationFilter.class)
// custom Token based authentication based on the header previously given to the client
.addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService), UsernamePasswordAuthenticationFilter.class);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
@Override
protected UserDetailsService userDetailsService() {
return userDetailsService;
}
}
.antMatchers("/resources/**").permitAll() - 甚至应该允许访问 resources/templates
我真的不明白为什么它不呈现网页内容 拜托,你能给我一些提示吗?
EDIT1
控制器:
@RestController
public class GreetingController {
@RequestMapping("/greeting")
public String greeting(@RequestParam(value="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name);
return "greeting";
}
}
根据 Spring 指南:Building a RESTful Web Service
A key difference between a traditional MVC controller and the RESTful web service controller above is the way that the HTTP response body is created. Rather than relying on a view technology to perform server-side rendering of the greeting data to HTML, this RESTful web service controller simply populates and returns a Greeting object. The object data will be written directly to the HTTP response as JSON.
因此在您的情况下 return "greetings" 在 JSON 中。如果你想让它return页面greeting.html,你应该使用正常的@Controller
.