• 32
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

概要

Spring SecurityとSpring MVCをxmlを使わずに設定してみた際のメモ。

完全なソースはGutHub

設定内容

  • 認証エラーの場合はログインページを表示する
  • 但し、Ajaxリクエストの場合はHTTPステータス401を返す
  • Thymeleafでsec:authorize="hasRole('ROLE_ADMIN')"のように、ロールによって表示を切り替えられるようにする

必要な依存関係

使用する主なモジュールとバージョン

  • SpringSecurity : 4.0.0.M1
  • SpringMVC : 4.0.5.RELEASE
  • Thymeleaf : 2.1.3.RELEASE

詳細はpom.xmを参照

SpringSecurityの設定

今回はAjaxリクエストの場合はログインページにリダイレクトするのではなくて、HTTPステータス401を返したいので、リクエストヘッダにX-Requested-With: XMLHttpRequestがあった場合のAuthenticationEntryPointを追加しています。

WebSecurityConfig
@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("admin").password("admin").roles("ADMIN").and()
            .withUser("user").password("user").roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers(
                    "/",
                    "/css/**",
                    "/login",
                    "/logout").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .and()
            .logout()
                .logoutRequestMatcher(logoutRequestMatcher())
                .invalidateHttpSession(true)
                .and()
            .csrf()
                .and()
            .exceptionHandling()
                .defaultAuthenticationEntryPointFor(
                    ajaxAuthenticationEntryPoint(),
                    ajaxRequestMatcher()
                );
    }

    @Bean
    public AuthenticationEntryPoint ajaxAuthenticationEntryPoint() {
    return new AuthenticationEntryPoint() {
        @Override
        public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        }
    };
    }

    @Bean
    public RequestMatcher ajaxRequestMatcher() {
    return new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest");
    }

    @Bean
    public RequestMatcher logoutRequestMatcher() {
    return new AntPathRequestMatcher("/logout");
    }

}

SpringMVCの設定

リソースハンドラとビューを返すだけのコントローラーを追加しています。
それから@Import(ThymeleafConfig.class)でThymeleafの設定をインポート。

WebMvcConfig
@Configuration
@EnableWebMvc
@Import(ThymeleafConfig.class)
@ComponentScan(
        basePackageClasses = {AjaxTestController.class}
)
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/css/**").addResourceLocations("/WEB-INF/views/css/");
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
        registry.addViewController("/login").setViewName("login");
        registry.addViewController("/member").setViewName("member");
    }
}

Tymeleafの設定

ThymeleafとSpringSecurityを連携するためにSpringSecurityDialectを追加。
開発中はキャッシュされない方がいいのでresolver.setCacheable(false);
それから文字コードの設定は2箇所あるので注意。

ThymeleafConfig
@Configuration
public class ThymeleafConfig {

    private final String CHARACTER_ENCODING = "UTF-8";

    @Bean
    public ServletContextTemplateResolver templateResolver() {
        ServletContextTemplateResolver resolver
                = new ServletContextTemplateResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".html");
        resolver.setTemplateMode("HTML5");
        resolver.setCharacterEncoding(CHARACTER_ENCODING);
        resolver.setCacheable(false);
        return resolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {
        SpringTemplateEngine engine = new SpringTemplateEngine();
        engine.setTemplateResolver(templateResolver());
        engine.addDialect(springSecurityDialect());
        return engine;
    }

    @Bean
    public ThymeleafViewResolver thymeleafViewResolver() {
        ThymeleafViewResolver resolver = new ThymeleafViewResolver();
        resolver.setTemplateEngine(templateEngine());
        resolver.setCharacterEncoding(CHARACTER_ENCODING);
        return resolver;
    }

    @Bean
    public IDialect springSecurityDialect() {
        SpringSecurityDialect dialect = new SpringSecurityDialect();
        return dialect;
    }
}