Spring MVC(3.2.5)アプリケーションとSpring Security(3.2)を使用しています。
このメソッドでSecurityConfig.classを構成しました:
_@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/*").permitAll().and()
.formLogin().successHandler(successHandler)
.defaultSuccessUrl("/")
.failureHandler(failureHandler).failureUrl("/login?error=true")
.permitAll().and().logout()
.permitAll();
http.authorizeRequests().antMatchers("/resources/**").permitAll();
http.authorizeRequests().antMatchers("/welcome").permitAll();
http.authorizeRequests().antMatchers("/secure/*").authenticated();
http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").anyRequest().authenticated();
}
_
Springセキュリティー(3.2)では、CSRFを有効にしています。有効にすることは良い考えだと思います。
私のコントローラーSignInControllerにはparamsを持つ2つのメソッドが含まれています:
[〜#〜] edit [〜#〜]:パラメータに_action=
_を追加
_@RequestMapping(value = "/signup")
public ModelAndView signup() {
boolean auth = SecurityContextHolder.getContext().getAuthentication() == null ? false
: SecurityContextHolder.getContext().getAuthentication()
.isAuthenticated()
&& (SecurityContextHolder.getContext()
.getAuthentication().getPrincipal() instanceof User);
ModelAndView result = null;
if (auth) {
result = new ModelAndView("redirect:" + "/");
} else {
UserForm user = new UserForm();
result = new ModelAndView("registration", "userForm", user);
}
return result;
}
@RequestMapping(value = "/register", params = "action=signup")
public ModelAndView registration(
@ModelAttribute(value = "userForm") @Valid UserForm userForm,
BindingResult result, HttpServletRequest request) {
if (result.hasErrors()) {
return new ModelAndView("registration");
}
Member member = profileFacade.registerNewUser(userForm);
return new ModelAndView("registration", "member", member);
}
@RequestMapping(value = "/register", params = "action=cancel")
public ModelAndView cancelRegistration() {
return new ModelAndView("redirect:" + "/");
}
_
そして最後に、JUnitテストがあります:
_@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = { WebConfiguration.class,
JpaConfiguration.class, LoggingConfiguration.class,
SecurityConfig.class, DataSourceEmbeddedConfiguration.class,
DataSourceMySqlConfig.class, BaseValidatorConfiguration.class })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@ActiveProfiles("dev")
public class SignInControllerTest {
@Autowired
private WebApplicationContext webApplicationContext;
@Autowired
private MockHttpSession session;
@Autowired
private MockHttpServletRequest request;
@Autowired
private FilterChainProxy springSecurityFilterChain;
private MockMvc mockMvc;
@Before
public void setUp() throws ServletException {
SecurityContextHolderAwareRequestFilter scharf = new SecurityContextHolderAwareRequestFilter();
scharf.afterPropertiesSet();
this.mockMvc = MockMvcBuilders
.webAppContextSetup(this.webApplicationContext)
.addFilters(springSecurityFilterChain).dispatchOptions(true).build();
SecurityContextHolder.getContext().setAuthentication(null);
}
@Test
public void signup() throws Exception {
mockMvc.perform(get("/signup")).andExpect(status().isOk())
.andExpect(model().attributeExists("userForm"));
}
@Test
@Transactional
@Rollback(true)
public void register() throws Exception {
UserForm form = new UserForm();
form.setEmail("[email protected]");
form.setUsername("aokije");
form.setPassword("klo,ksff");
form.setConfirmedPassword("klo,ksff");
mockMvc.perform(post("/register").param("action", "signup")).andExpect(status().isOk());
}
}
_
[〜#〜] edit [〜#〜]:mockMvc.performを更新します。SecurityConfig.classのhttp.csrf().disable()
で正常に動作しているためです
テストsignup完全に実行されますが、registerエラー403を返します。I多くのことを試みましたが、私はいつもこのエラーを受け取りました。
ブラウザで_http://localhost:8080/register?signup
_を試すと、正常に動作しています。
_[〜#〜]編集[〜#〜]_
ログ:
_2014-02-13 22:00:14,695 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'permitAll', for org.springframework.security.config.annotation.web.configurers.PermitAllSupport$ExactUrlRequestMatcher@52ee705c
2014-02-13 22:00:14,696 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'permitAll', for org.springframework.security.config.annotation.web.configurers.PermitAllSupport$ExactUrlRequestMatcher@2412d28d
2014-02-13 22:00:14,697 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'permitAll', for org.springframework.security.config.annotation.web.configurers.PermitAllSupport$ExactUrlRequestMatcher@4fbd397b
2014-02-13 22:00:14,697 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'permitAll', for Ant [pattern='/logout']
2014-02-13 22:00:14,698 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'permitAll', for org.springframework.security.config.annotation.web.configurers.PermitAllSupport$ExactUrlRequestMatcher@1008e323
2014-02-13 22:00:14,699 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'permitAll', for Ant [pattern='/*']
2014-02-13 22:00:14,700 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'permitAll', for Ant [pattern='/resources/**']
2014-02-13 22:00:14,700 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'permitAll', for Ant [pattern='/welcome']
2014-02-13 22:00:14,700 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'authenticated', for Ant [pattern='/secure/*']
2014-02-13 22:00:14,701 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'hasRole('ROLE_ADMIN')', for Ant [pattern='/admin/**']
2014-02-13 22:00:14,701 [ExpressionBasedFilterInvocationSecurityMetadataSource] processMap Adding web access control expression 'authenticated', for org.springframework.security.web.util.matcher.AnyRequestMatcher@1
2014-02-13 22:00:14,703 [FilterSecurityInterceptor] afterPropertiesSet Validated configuration attributes
2014-02-13 22:00:14,704 [FilterSecurityInterceptor] afterPropertiesSet Validated configuration attributes
2014-02-13 22:00:14,734 [DefaultSecurityFilterChain] <init> Creating filter chain: org.springframework.security.web.util.matcher.AnyRequestMatcher@1, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@10174779, org.springframework.security.web.context.SecurityContextPersistenceFilter@68736a7e, org.springframework.security.web.header.HeaderWriterFilter@728e5d0d, org.springframework.security.web.csrf.CsrfFilter@6e7a918b, org.springframework.security.web.authentication.logout.LogoutFilter@430e85e7, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@55eda087, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@290c7ca, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@6dd90afc, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@12eb6a0f, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@6855612f, org.springframework.security.web.session.SessionManagementFilter@410a11a2, org.springframework.security.web.access.ExceptionTranslationFilter@59e15580, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@2257a0]
2014-02-13 22:00:14,859 [FilterChainProxy] doFilter /register at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2014-02-13 22:00:14,863 [FilterChainProxy] doFilter /register at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2014-02-13 22:00:14,863 [HttpSessionSecurityContextRepository] readSecurityContextFromSession HttpSession returned null object for SPRING_SECURITY_CONTEXT
2014-02-13 22:00:14,863 [HttpSessionSecurityContextRepository] loadContext No SecurityContext was available from the HttpSession: org.springframework.mock.web.MockHttpSession@4c4b529f. A new one will be created.
2014-02-13 22:00:14,864 [FilterChainProxy] doFilter /register at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2014-02-13 22:00:14,865 [HstsHeaderWriter] writeHeaders Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@5ab39e58
2014-02-13 22:00:14,865 [FilterChainProxy] doFilter /register at position 4 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
2014-02-13 22:00:14,866 [CsrfFilter] doFilterInternal Invalid CSRF token found for http://localhost/register
2014-02-13 22:00:14,866 [HttpSessionSecurityContextRepository] saveContext SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2014-02-13 22:00:14,866 [SecurityContextPersistenceFilter] doFilter SecurityContextHolder now cleared, as request processing completed
_
私たちを手伝ってくれますか ?
どうもありがとう
[〜#〜]編集[〜#〜]
最後に、別のクラス(注釈)にバグがありました。私はこれで修正します:
_HttpSessionCsrfTokenRepository httpSessionCsrfTokenRepository = new HttpSessionCsrfTokenRepository();
CsrfToken csrfToken = httpSessionCsrfTokenRepository
.generateToken(request);
Map map = new HashMap();
map.put("userForm", form);
map.put("org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN",
csrfToken);
this.mockMvc
.perform(
post("/register")
.param("signup", "")
.param("_csrf", csrfToken.getToken())
.sessionAttrs(map)).andExpect(status().isOk());
_
パラメータcsrfとsessionAttrsは必須です。
投稿リクエストでは、フォームにCSRFトークンを追加する必要があります。したがって、テスト中にコードを渡す必要があります:( "それは私のマシンで動作します" :))
String TOKEN_ATTR_NAME = "org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN";
// ...
HttpSessionCsrfTokenRepository httpSessionCsrfTokenRepository = new HttpSessionCsrfTokenRepository();
CsrfToken csrfToken = httpSessionCsrfTokenRepository.generateToken(new MockHttpServletRequest());
this.mockMvc.perform(
post("yourpath")
.sessionAttr(TOKEN_ATTR_NAME, csrfToken)
.param(csrfToken.getParamName(), csrfToken.getToken())...
2番目のこと:「登録」メソッドが投稿リクエストを処理することを確認しますか?RequestMappingはデフォルトで「GET」に設定されていませんか?(ここでは間違っている可能性があります)
私はこの質問がかなり古いことを知っていますが、これはいくつかのクエリに対するGoogleでの最初の結果の1つであり、このアプローチははるかに優れていると思います spring.ioブログで説明
1)mockMvc
をSpring Securityサポートで簡単に作成できるため、setUp()
ははるかに短くなります。
_@Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.apply(springSecurity())
.build();
}
_
2)org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf()
を使用して、次のようにテスト要求に正しいCSRFトークンを入力できます。
_mockMvc.perform(post("/register")
.with(csrf())
.param("action", "signup"))
.andExpect(status().isOk());
_