将 Spring Security 添加到现有 Spring Web App(使用 JavaConfig)
Posted
技术标签:
【中文标题】将 Spring Security 添加到现有 Spring Web App(使用 JavaConfig)【英文标题】:Adding Spring Security to an existing Spring Web App (using JavaConfig) 【发布时间】:2014-03-07 00:38:45 【问题描述】:我有一个 Spring MVC Rest Web App,我正在为其添加一个 Spring Security 层。
当我浏览Spring documentation 时,我无法理解第 3.1.3 节的含义。我正在复制/粘贴以下部分的内容。
If we were using Spring elsewhere in our application we probably already had a WebApplicationInitializer that is loading our Spring Configuration. If we use the previous configuration we would get an error. Instead, we should register Spring Security with the existing ApplicationContext. For example, if we were using Spring MVC our SecurityWebApplicationInitializer would look something like the following:
import org.springframework.security.web.context.*;
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer
This would simply only register the springSecurityFilterChain Filter for every URL in your application. After that we would ensure that SecurityConfig was loaded in our existing ApplicationInitializer. For example, if we were using Spring MVC it would be added in the getRootConfigClasses()
public class MvcWebApplicationInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer
@Override
protected Class<?>[] getRootConfigClasses()
return new Class[] SecurityConfig.class ;
// ... other overrides ...
所以,我已经有了以下内容
an Initializer.java (replacement of web.xml)
Config.java - Root Context
RestServlet.java - Servlet Context
这是我的 Initializer.java
public class Initializer implements WebApplicationInitializer
public void onStartup(ServletContext container) throws ServletException
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext =
new AnnotationConfigWebApplicationContext();
rootContext.register(Config.class);
// Manage the lifecycle of the root application context
container.addListener(new ContextLoaderListener(rootContext));
// container.addListener(new ContextLoaderListener(rootContext));
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext =
new AnnotationConfigWebApplicationContext();
dispatcherContext.register(RestServlet.class);
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher =
container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
为了添加 Spring Security 层,我添加了以下内容
SecurityConfig.java
SecurityInitializer.java
SecurityConfig.java(这是为了测试使用内存认证细节)。
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
SecurityInitializer.java
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer
protected Class<?>[] getRootConfigClasses()
return new Class[] SecurityConfig.class ;
现在,问题是我不确定如何执行这些步骤。我不知道(基于文档的第 3.2.3 节)我是否应该扩展 AbstractSecurityWebApplicationInitializer 或 AbstractAnnotationConfigDispatcherServletInitializer。
另一个问题是这是一个 REST 应用程序。我没有任何返回 jsps 的控制器(我不想这样做!)。我的最终目标是使用 OAuth2,生成令牌并将其发布到前端 web 应用程序(基于 Angular),并以这种方式保护 REST api。还要在此基础上添加 Facebook 和 Google+ 登录。但是我正在采取弹簧安全措施,我被困在这里。想知道走这条路的人是否已经可以分享他们的智慧。
【问题讨论】:
你在这方面取得过成功吗? @end-user 已经有一段时间了,所以我不记得我究竟做了什么来修复它,但这是当前工作配置作为参考github.com/billrive/billrive/tree/master/billrive-app/src/main/… 【参考方案1】:您可以将其作为普通的@Configuration 类注入,如下所示:
@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter
@Autowired
FooUserDetailsService fooUserDetailsService;
@Autowired
PasswordEncoder passwordEncoder;
@Bean
public PasswordEncoder passwordEncoder()
return new BCryptPasswordEncoder();
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth.userDetailsService(this.fooUserDetailsService).passwordEncoder(passwordEncoder);
@Override
protected void configure(HttpSecurity http) throws Exception
http
.authorizeRequests()
.antMatchers("/signup").anonymous()
.antMatchers("/public/**").permitAll()
.antMatchers("/auth/**").permitAll()
.antMatchers("/api/**").hasRole("USER")
.antMatchers("/**").hasAnyRole("USER", "ADMIN")
.and()
.csrf().disable()
.formLogin()
.loginProcessingUrl("/j_spring_security_check")
.loginPage("/auth").failureUrl("/auth")
.usernameParameter("j_username").passwordParameter("j_password")
.defaultSuccessUrl("/")
.and()
.logout()
.logoutUrl("/j_spring_security_logout")
.logoutSuccessUrl("/auth");
此处的路径只是示例,您可能必须重写它以满足您的需求,例如,如果这是您正在制作的纯 REST API,则删除表单登录内容。
要加载它,您可以执行以下操作:
public class WebApplicationInitialiser implements WebApplicationInitializer
private static Class<?>[] configurationClasses = new Class<?>[]
WebSecurityConfiguration.class
;
使用createContext(configurationClasses);
将类(我假设您有多个)添加到上下文中
我希望这会有所帮助。
【讨论】:
【参考方案2】:您需要执行的后续步骤之一是完成“3.4. 授权请求”部分。您将需要创建控制器以使您能够创建 RESTful 服务。您可以返回 JSON 或 XML,而不是返回 JSP 页面。要创建 RESTful Web 服务,请参考 Spring.io 文档 (http://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch18s02.html),这是一个指向 spring 3.0 的链接,可能有一个更新的版本可用于 Spring 4.0,但这个链接应该为您提供足够的信息来帮助您开始事情的 REST 方面。设置好 REST 请求后,例如 @RequestMapping("/users/userid", method=RequestMethod.GET)
。
那么您现在可以按照第 3.4 节进行操作,即.antMatchers("/users/**").hasRole("USER")
下一步是查看身份验证并设置包含用户/密码的数据源,这里有 2 个选项我建议先使用内存配置,请参阅“3.5.1.内存身份验证”了解更多信息信息。
【讨论】:
谢谢。但我无法通过第 3.2.3 节。我不确定如何扩展 AbstractSecurityWebApplicationInitializer 和/或 AbstractAnnotationConfigDispatcherServletInitializer 以及如何与现有的 Config/Initializer 类集成。 如果您已经有一个实现 WebApplicationInitializer 并实现 onStartup 方法(加载您的 spring 应用程序配置)的类“WebAppInitializer”,那么您将使用“AbstractSecurityWebApplicationInitializer”。否则,您将寻求使用 AbstractSecurityWebApplicationInitializer 方法。【参考方案3】:实际上注册了两个上下文加载器侦听器将触发与框架相关的异常。这两种 context-loader 监听器注册场景发生在一个已经通过 java-config 修饰了 DispatcherServlet
配置的情况下,通过扩展 AbstractAnnotationConfigDispatcherServletInitializer
-> root-config 类将注册到 ContextLoaderListener
上下文中;现在通过扩展AbstractSecurityWebApplicationInitializer
也启用了安全方面,如果给出了任何根配置类,将尝试创建另一个ContextLoaderListener
。因此,建议您是否已经拥有带有根相关配置 bean 的 ContextLoaderListener
,以避免通过 AbstractSecurityWebApplicationInitializer
注册其他根相关配置 bean。
【讨论】:
以上是关于将 Spring Security 添加到现有 Spring Web App(使用 JavaConfig)的主要内容,如果未能解决你的问题,请参考以下文章
使用 spring-security-core 插件将 Facebook 登录 (oauth) 与现有 grails 应用程序集成
是否可以将相同站点属性添加到 Spring Security CSRF 的 .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFal
您能否将 Workspace Security 添加到现有 Magnolia 工作区?
将标头添加到 oauth/token 响应(spring-security)