spring之将 Spring Security 添加到现有的 Spring Web App(使用 JavaConfig)

java哥 阅读:15 2024-02-27 23:08:18 评论:0

我有一个 Spring MVC Rest Web 应用程序,我正在为其添加一层 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 的 Controller (我也不想!)。我的最终目标是使用 OAuth2,生成 token 并将其发布到前端 web 应用程序(基于 Angular),并以这种方式保护 REST api。还要在此基础上添加 Facebook 和 Google+ 登录。但是我正在采取 Spring 安全措施,但我被困在这里。想知道是否有任何已经走上这条道路的人可以分享他们的智慧。

请您参考如下方法:

您可以将其作为普通的@Configuration 类注入(inject),如下所示:

@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);

将类(因为我假设你有多个)添加到上下文中

我希望这对您有所帮助。


标签:java
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号