概要
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;
	}
}