Spring 安全抛出 javax.servlet.ServletException:无法解析名称为 'j_spring_security_check' 的视图
Spring security throws javax.servlet.ServletException: Could not resolve view with name 'j_spring_security_check'
我正在尝试添加 Spring 安全性 自定义登录页面 和 访问数据库 到我的 Spring MVC 应用程序。似乎我的映射是错误的,因为它无法映射 j_spring_security_check
.
为了解决这个问题,我查看了以下页面 1,2,,但仍无法解决问题。
如果您没有太多时间,请阅读下面的第 2 部分,这是问题的编辑部分开始的地方。否则,请同时阅读 PART 1 和 PART 2。
第 1 部分
我还在我的 web.xml
文件中添加了以下行,但应用程序 returns 出现异常。
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Caused by: java.lang.IllegalStateException: Duplicate Filter registration for 'springSecurityFilterChain'. Check to ensure the Filter is only configured once.
at org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer.registerFilter(AbstractSecurityWebApplicationInitializer.java:215)
at org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer.insertSpringSecurityFilterChain(AbstractSecurityWebApplicationInitializer.java:147)
at org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer.onStartup(AbstractSecurityWebApplicationInitializer.java:121)
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:175)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5423)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 6 more
Jun 13, 2015 2:44:54 PM org.apache.catalina.core.ContainerBase startInternal
SEVERE: A child container failed during start
java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost]]
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:188)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1123)
at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:302)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:443)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:732)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.startup.Catalina.start(Catalina.java:691)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:322)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:456)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1131)
at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:800)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 6 more
Jun 13, 2015 2:44:54 PM org.apache.catalina.startup.Catalina start
SEVERE: The required Server component failed to start so Tomcat is unable to start.
org.apache.catalina.LifecycleException: Failed to start component [StandardServer[8005]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
at org.apache.catalina.startup.Catalina.start(Catalina.java:691)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:322)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:456)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardService[Catalina]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:732)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 7 more
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:443)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 9 more
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1131)
at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:302)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 11 more
不添加过滤器一旦提交表单,请求将被以下控制器捕获。
@Controller
public class MainController {
@RequestMapping("/{viewName}")
public String index(@PathVariable String viewName) {
...
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<listener>
<listener-class>org.apache.tiles.extras.complete.CompleteAutoloadTilesListener</listener-class>
</listener>
<servlet>
<servlet-name>my</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- <listener> -->
<!-- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> -->
<!-- </listener> -->
<!-- <filter> -->
<!-- <filter-name>springSecurityFilterChain</filter-name> -->
<!-- <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> -->
<!-- </filter> -->
<!-- <filter-mapping> -->
<!-- <filter-name>springSecurityFilterChain</filter-name> -->
<!-- <url-pattern>/*</url-pattern> -->
<!-- </filter-mapping> -->
<servlet-mapping>
<servlet-name>my</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/config/my-security.xml
</param-value>
</context-param>
</web-app>
我的-security.xml
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<http auto-config="true" access-denied-page="/notFound.jsp"
use-expressions="true">
<intercept-url pattern="/" access="permitAll" />
</http>
<!-- <beans:import resource="security-db.xml" /> -->
<authentication-manager>
<authentication-provider>
<user-service>
<user name="alex" password="123456" authorities="ROLE_USER" />
<user name="mkyong" password="123456" authorities="ROLE_USER, ROLE_ADMIN" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
AppConfig.java
@EnableWebMvc
@Configuration
@ComponentScan({ "com.myproject.*" })
@EnableTransactionManagement
@Import({ SecurityConfig.class })
public class AppConfig {
@Bean
public SessionFactory sessionFactory() {
LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(
dataSource());
builder.scanPackages("com.myproject.model").addProperties(
getHibernateProperties());
return builder.buildSessionFactory();
}
private Properties getHibernateProperties() {
Properties prop = new Properties();
prop.put("hibernate.format_sql", "true");
prop.put("hiberate.show_sql", "true");
prop.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
return prop;
}
@Bean(name = "dataSource")
public BasicDataSource dataSource() {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/test");
ds.setUsername("jack");
ds.setPassword("jack");
return ds;
}
@Bean
public HibernateTransactionManager txManager() {
return new HibernateTransactionManager(sessionFactory());
}
}
SecurityConfig.java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("userDetailsService")
UserDetailsService userDetailsService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(
passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/profile/**")
.access("hasRole('ADMIN')").and().formLogin()
.loginPage("/signin").failureUrl("/signin?error")
.usernameParameter("username").passwordParameter("password")
.and().logout().logoutSuccessUrl("/index").and().csrf().and()
.exceptionHandling().accessDeniedPage("/403");
}
@Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
}
SpringMVCInitializer.java
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class SpringMvcInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { AppConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
LoginController.java
@Controller
public class LoginController {
@RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView login(
@RequestParam(value = "error", required = false) String error,
@RequestParam(value = "logout", required = false) String logout) {
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", "Invalid username and password!");
}
if (logout != null) {
model.addObject("msg", "You've been logged out successfully.");
}
model.setViewName("login");
return model;
}
}
**
第 2 部分
根据 Thomas 的建议,我将代码更改如下
**
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<listener>
<listener-class>org.apache.tiles.extras.complete.CompleteAutoloadTilesListener</listener-class>
</listener>
<servlet>
<servlet-name>my</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>my</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
AppConfig.java
@EnableWebMvc
@Configuration
@ComponentScan({ "com.myproject" })
@EnableTransactionManagement
@Import({ SecurityConfig.class })
public class AppConfig {
@Bean
public SessionFactory sessionFactory() {
LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(
dataSource());
builder.scanPackages("com.myproject.model").addProperties(
getHibernateProperties());
return builder.buildSessionFactory();
}
private Properties getHibernateProperties() {
Properties prop = new Properties();
prop.put("hibernate.format_sql", "true");
prop.put("hiberate.show_sql", "true");
prop.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
return prop;
}
@Bean(name = "dataSource")
public BasicDataSource dataSource() {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/test");
ds.setUsername("jack");
ds.setPassword("jack");
return ds;
}
@Bean
public HibernateTransactionManager txManager() {
return new HibernateTransactionManager(sessionFactory());
}
}
SecurityConfig.java
@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("userDetailsService")
UserDetailsService userDetailsService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
// auth.userDetailsService(userDetailsService).passwordEncoder(
// passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/profile/**")
.access("hasRole('ADMIN')").and().formLogin()
.loginPage("/login").failureUrl("/login?error")
.and().logout().logoutSuccessUrl("/index").and().csrf().and()
.exceptionHandling().accessDeniedPage("/403");
}
@Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
}
SpringMVCInitializer.java
public class SpringMvcInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { AppConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
主控制器
@Controller
public class MainController {
@RequestMapping("/{viewName}")
public String index(@PathVariable String viewName) {
System.err.println("View Name is :" + viewName);
if (isValidView(viewName)) {
return viewName;
}
return null;
}
关于MainController,这是我处理静态页面的方式,例如www.myproject.com/index,www.myproject.com/contactus等。关于这个问题我的另一个问题是
您的代码中存在几个问题。最重要的一点是,您混合了 Java 配置和 XML 配置以实现 Spring 安全性。决定您喜欢使用哪种配置。在我的回答中,我将重点关注基于 Java 的配置,因为我将从您的代码中完全删除 XML 配置。
在您的情况下,默认情况下 @EnableWebSecurity
注释已经注册了适当的过滤器。但是如果你使用的是 Spring MVC,它应该是 @EnableWebMvcSecurity
.
另外,看看你的HttpSecurity
配置:
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/profile/**")
.access("hasRole('ADMIN')").and().formLogin()
.loginPage("/signin").failureUrl("/signin?error")
.usernameParameter("username").passwordParameter("password")
.and().logout().logoutSuccessUrl("/index").and().csrf().and()
.exceptionHandling().accessDeniedPage("/403");
}
您显然是在告诉登录页面将位于 /signin
,但在您的 LoginController 中映射是针对 /login
。你配置 .usernameParameter("username") .passwordParameter("password")
做什么? Spring 安全默认配置中已经这样做了。
您还应该添加 SecurityInitializer
class,它在 Spring Security 3.2 中可能如下所示:
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
public SecurityInitializer() {
super(SecurityConfig.class);
}
}
总而言之,将 Spring 安全性添加到您的项目的基本步骤如下:
- 为 Spring 安全性添加适当的(Maven,Gradle)依赖项;
- 配置 Spring 安全 class 注释
@EnableWebMvcSecurity
,特别是在 configureGlobal(...)
和 configure(...)
方法中;
- 注册 class 扩展
AbstractSecurityWebApplicationInitializer
;
- 在您的控制器中提供登录页面的映射,并在 JSP 页面中写下自定义表单。
基本登录表单如下所示:
<form name='loginForm' method='POST'>
<table>
<tr>
<td>User:</td>
<td><input type='text' name='username' value=''></td>
</tr>
<tr>
<td>Password:</td>
<td><input type='password' name='password' /></td>
</tr>
<tr>
<td colspan='2'><input name="submit" type="submit"
value="submit" /></td>
</tr>
</table>
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
</form>
这些基本步骤可在您的项目中启用 Spring 安全性。有关更多信息,好的教程是:
http://docs.spring.io/spring-security/site/docs/3.2.x/guides/hellomvc.html
http://docs.spring.io/spring-security/site/docs/3.2.x/guides/form.html
祝你好运:)
我强烈建议您遵循 Java 或 XML 配置。我个人比较喜欢Java配置
- 删除所有 Spring 与安全相关的 XML 配置并创建以下内容
文件。
将权限地址修改为您拥有的任何地址。
public class MessageSecurityWebApplicationInitializer extends
AbstractSecurityWebApplicationInitializer { //register the springSecurityFilterChain with the war
}
public class MessageWebApplicationInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { SecurityConfig.class }; //make sure your config file gets loaded
}
@Override
protected Class<?>[] getServletConfigClasses() {
// TODO Auto-generated method stub
return null;
}
@Override
protected String[] getServletMappings() {
// TODO Auto-generated method stub
return null;
}
@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
System.err.println("in here");
auth.inMemoryAuthentication().withUser("user@yahoo.com")
.password("password").roles("USER"); //access to inmemory credentials
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/resources/**", "/", "/index", "/aboutus")
.permitAll() //allow access to your static pages and resources
.antMatchers("/profile/**")
.hasRole("USER") //profile address is only available to users ( do not need to add ROLE_ as Spring does it for you)
.and() //and is equivalent of end tag in XML
.formLogin().loginPage("/signin").failureUrl("/signin?error")
.permitAll().and().logout().logoutUrl("/singout").permitAll();
}
有关进一步说明和访问数据库的信息,请参阅 documentation
我正在尝试添加 Spring 安全性 自定义登录页面 和 访问数据库 到我的 Spring MVC 应用程序。似乎我的映射是错误的,因为它无法映射 j_spring_security_check
.
为了解决这个问题,我查看了以下页面 1,2,
如果您没有太多时间,请阅读下面的第 2 部分,这是问题的编辑部分开始的地方。否则,请同时阅读 PART 1 和 PART 2。
第 1 部分
我还在我的 web.xml
文件中添加了以下行,但应用程序 returns 出现异常。
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Caused by: java.lang.IllegalStateException: Duplicate Filter registration for 'springSecurityFilterChain'. Check to ensure the Filter is only configured once.
at org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer.registerFilter(AbstractSecurityWebApplicationInitializer.java:215)
at org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer.insertSpringSecurityFilterChain(AbstractSecurityWebApplicationInitializer.java:147)
at org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer.onStartup(AbstractSecurityWebApplicationInitializer.java:121)
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:175)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5423)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 6 more
Jun 13, 2015 2:44:54 PM org.apache.catalina.core.ContainerBase startInternal
SEVERE: A child container failed during start
java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost]]
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:188)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1123)
at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:302)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:443)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:732)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.startup.Catalina.start(Catalina.java:691)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:322)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:456)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1131)
at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:800)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 6 more
Jun 13, 2015 2:44:54 PM org.apache.catalina.startup.Catalina start
SEVERE: The required Server component failed to start so Tomcat is unable to start.
org.apache.catalina.LifecycleException: Failed to start component [StandardServer[8005]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
at org.apache.catalina.startup.Catalina.start(Catalina.java:691)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:322)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:456)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardService[Catalina]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:732)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 7 more
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:443)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 9 more
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1131)
at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:302)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 11 more
不添加过滤器一旦提交表单,请求将被以下控制器捕获。
@Controller
public class MainController {
@RequestMapping("/{viewName}")
public String index(@PathVariable String viewName) {
...
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<listener>
<listener-class>org.apache.tiles.extras.complete.CompleteAutoloadTilesListener</listener-class>
</listener>
<servlet>
<servlet-name>my</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- <listener> -->
<!-- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> -->
<!-- </listener> -->
<!-- <filter> -->
<!-- <filter-name>springSecurityFilterChain</filter-name> -->
<!-- <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> -->
<!-- </filter> -->
<!-- <filter-mapping> -->
<!-- <filter-name>springSecurityFilterChain</filter-name> -->
<!-- <url-pattern>/*</url-pattern> -->
<!-- </filter-mapping> -->
<servlet-mapping>
<servlet-name>my</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/config/my-security.xml
</param-value>
</context-param>
</web-app>
我的-security.xml
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<http auto-config="true" access-denied-page="/notFound.jsp"
use-expressions="true">
<intercept-url pattern="/" access="permitAll" />
</http>
<!-- <beans:import resource="security-db.xml" /> -->
<authentication-manager>
<authentication-provider>
<user-service>
<user name="alex" password="123456" authorities="ROLE_USER" />
<user name="mkyong" password="123456" authorities="ROLE_USER, ROLE_ADMIN" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
AppConfig.java
@EnableWebMvc
@Configuration
@ComponentScan({ "com.myproject.*" })
@EnableTransactionManagement
@Import({ SecurityConfig.class })
public class AppConfig {
@Bean
public SessionFactory sessionFactory() {
LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(
dataSource());
builder.scanPackages("com.myproject.model").addProperties(
getHibernateProperties());
return builder.buildSessionFactory();
}
private Properties getHibernateProperties() {
Properties prop = new Properties();
prop.put("hibernate.format_sql", "true");
prop.put("hiberate.show_sql", "true");
prop.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
return prop;
}
@Bean(name = "dataSource")
public BasicDataSource dataSource() {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/test");
ds.setUsername("jack");
ds.setPassword("jack");
return ds;
}
@Bean
public HibernateTransactionManager txManager() {
return new HibernateTransactionManager(sessionFactory());
}
}
SecurityConfig.java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("userDetailsService")
UserDetailsService userDetailsService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(
passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/profile/**")
.access("hasRole('ADMIN')").and().formLogin()
.loginPage("/signin").failureUrl("/signin?error")
.usernameParameter("username").passwordParameter("password")
.and().logout().logoutSuccessUrl("/index").and().csrf().and()
.exceptionHandling().accessDeniedPage("/403");
}
@Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
}
SpringMVCInitializer.java
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class SpringMvcInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { AppConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
LoginController.java
@Controller
public class LoginController {
@RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView login(
@RequestParam(value = "error", required = false) String error,
@RequestParam(value = "logout", required = false) String logout) {
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", "Invalid username and password!");
}
if (logout != null) {
model.addObject("msg", "You've been logged out successfully.");
}
model.setViewName("login");
return model;
}
}
**
第 2 部分
根据 Thomas 的建议,我将代码更改如下
**
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<listener>
<listener-class>org.apache.tiles.extras.complete.CompleteAutoloadTilesListener</listener-class>
</listener>
<servlet>
<servlet-name>my</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>my</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
AppConfig.java
@EnableWebMvc
@Configuration
@ComponentScan({ "com.myproject" })
@EnableTransactionManagement
@Import({ SecurityConfig.class })
public class AppConfig {
@Bean
public SessionFactory sessionFactory() {
LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(
dataSource());
builder.scanPackages("com.myproject.model").addProperties(
getHibernateProperties());
return builder.buildSessionFactory();
}
private Properties getHibernateProperties() {
Properties prop = new Properties();
prop.put("hibernate.format_sql", "true");
prop.put("hiberate.show_sql", "true");
prop.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
return prop;
}
@Bean(name = "dataSource")
public BasicDataSource dataSource() {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/test");
ds.setUsername("jack");
ds.setPassword("jack");
return ds;
}
@Bean
public HibernateTransactionManager txManager() {
return new HibernateTransactionManager(sessionFactory());
}
}
SecurityConfig.java
@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("userDetailsService")
UserDetailsService userDetailsService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
// auth.userDetailsService(userDetailsService).passwordEncoder(
// passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/profile/**")
.access("hasRole('ADMIN')").and().formLogin()
.loginPage("/login").failureUrl("/login?error")
.and().logout().logoutSuccessUrl("/index").and().csrf().and()
.exceptionHandling().accessDeniedPage("/403");
}
@Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
}
SpringMVCInitializer.java
public class SpringMvcInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { AppConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
主控制器
@Controller
public class MainController {
@RequestMapping("/{viewName}")
public String index(@PathVariable String viewName) {
System.err.println("View Name is :" + viewName);
if (isValidView(viewName)) {
return viewName;
}
return null;
}
关于MainController,这是我处理静态页面的方式,例如www.myproject.com/index,www.myproject.com/contactus等。关于这个问题我的另一个问题是
您的代码中存在几个问题。最重要的一点是,您混合了 Java 配置和 XML 配置以实现 Spring 安全性。决定您喜欢使用哪种配置。在我的回答中,我将重点关注基于 Java 的配置,因为我将从您的代码中完全删除 XML 配置。
在您的情况下,默认情况下 @EnableWebSecurity
注释已经注册了适当的过滤器。但是如果你使用的是 Spring MVC,它应该是 @EnableWebMvcSecurity
.
另外,看看你的HttpSecurity
配置:
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/profile/**")
.access("hasRole('ADMIN')").and().formLogin()
.loginPage("/signin").failureUrl("/signin?error")
.usernameParameter("username").passwordParameter("password")
.and().logout().logoutSuccessUrl("/index").and().csrf().and()
.exceptionHandling().accessDeniedPage("/403");
}
您显然是在告诉登录页面将位于 /signin
,但在您的 LoginController 中映射是针对 /login
。你配置 .usernameParameter("username") .passwordParameter("password")
做什么? Spring 安全默认配置中已经这样做了。
您还应该添加 SecurityInitializer
class,它在 Spring Security 3.2 中可能如下所示:
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
public SecurityInitializer() {
super(SecurityConfig.class);
}
}
总而言之,将 Spring 安全性添加到您的项目的基本步骤如下:
- 为 Spring 安全性添加适当的(Maven,Gradle)依赖项;
- 配置 Spring 安全 class 注释
@EnableWebMvcSecurity
,特别是在configureGlobal(...)
和configure(...)
方法中; - 注册 class 扩展
AbstractSecurityWebApplicationInitializer
; - 在您的控制器中提供登录页面的映射,并在 JSP 页面中写下自定义表单。
基本登录表单如下所示:
<form name='loginForm' method='POST'>
<table>
<tr>
<td>User:</td>
<td><input type='text' name='username' value=''></td>
</tr>
<tr>
<td>Password:</td>
<td><input type='password' name='password' /></td>
</tr>
<tr>
<td colspan='2'><input name="submit" type="submit"
value="submit" /></td>
</tr>
</table>
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
</form>
这些基本步骤可在您的项目中启用 Spring 安全性。有关更多信息,好的教程是: http://docs.spring.io/spring-security/site/docs/3.2.x/guides/hellomvc.html http://docs.spring.io/spring-security/site/docs/3.2.x/guides/form.html
祝你好运:)
我强烈建议您遵循 Java 或 XML 配置。我个人比较喜欢Java配置
- 删除所有 Spring 与安全相关的 XML 配置并创建以下内容 文件。
将权限地址修改为您拥有的任何地址。
public class MessageSecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer { //register the springSecurityFilterChain with the war } public class MessageWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[] { SecurityConfig.class }; //make sure your config file gets loaded } @Override protected Class<?>[] getServletConfigClasses() { // TODO Auto-generated method stub return null; } @Override protected String[] getServletMappings() { // TODO Auto-generated method stub return null; } @Configuration @EnableWebMvcSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { System.err.println("in here"); auth.inMemoryAuthentication().withUser("user@yahoo.com") .password("password").roles("USER"); //access to inmemory credentials } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/resources/**", "/", "/index", "/aboutus") .permitAll() //allow access to your static pages and resources .antMatchers("/profile/**") .hasRole("USER") //profile address is only available to users ( do not need to add ROLE_ as Spring does it for you) .and() //and is equivalent of end tag in XML .formLogin().loginPage("/signin").failureUrl("/signin?error") .permitAll().and().logout().logoutUrl("/singout").permitAll(); }
有关进一步说明和访问数据库的信息,请参阅 documentation