SecurityContextHolder + @Async fixes and improvements (#930)
* @Async and Spring Security * @Async with SecurityContext propagated * Spring and @Async * Simulated Annealing algorithm * Simulated Annealing algorithm * Rebase * Rebase * SA further fixes * Slope One plus package refactoring * SlopeOne refactoring * Async improvements and fixes * Remove unnecessary bean * Final fixes to Spring Security @Async * Async Spring MVC
This commit is contained in:
parent
7844b1d4e4
commit
4018d45a2c
|
@ -1,7 +1,6 @@
|
|||
package org.baeldung.spring;
|
||||
|
||||
import org.baeldung.security.MySavedRequestAwareAuthenticationSuccessHandler;
|
||||
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -25,6 +24,7 @@ public class SecurityJavaConfig extends WebSecurityConfigurerAdapter {
|
|||
|
||||
public SecurityJavaConfig() {
|
||||
super();
|
||||
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -47,7 +47,7 @@ public class SecurityJavaConfig extends WebSecurityConfigurerAdapter {
|
|||
.antMatchers("/api/csrfAttacker*").permitAll()
|
||||
.antMatchers("/api/customer/**").permitAll()
|
||||
.antMatchers("/api/foos/**").authenticated()
|
||||
.antMatchers("/api/async/**").authenticated()
|
||||
.antMatchers("/api/async/**").permitAll()
|
||||
.and()
|
||||
.httpBasic()
|
||||
// .and()
|
||||
|
@ -67,13 +67,4 @@ public class SecurityJavaConfig extends WebSecurityConfigurerAdapter {
|
|||
return new SimpleUrlAuthenticationFailureHandler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MethodInvokingFactoryBean methodInvokingFactoryBean() {
|
||||
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
|
||||
methodInvokingFactoryBean.setTargetClass(SecurityContextHolder.class);
|
||||
methodInvokingFactoryBean.setTargetMethod("setStrategyName");
|
||||
methodInvokingFactoryBean.setArguments(new String[]{SecurityContextHolder.MODE_INHERITABLETHREADLOCAL});
|
||||
return methodInvokingFactoryBean;
|
||||
}
|
||||
|
||||
}
|
|
@ -3,6 +3,7 @@ package org.baeldung.spring;
|
|||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.web.servlet.ViewResolver;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
|
@ -13,6 +14,7 @@ import org.springframework.web.servlet.view.InternalResourceViewResolver;
|
|||
@Configuration
|
||||
@ComponentScan("org.baeldung.web")
|
||||
@EnableWebMvc
|
||||
@EnableAsync
|
||||
public class WebConfig extends WebMvcConfigurerAdapter {
|
||||
|
||||
public WebConfig() {
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.baeldung.web.controller;
|
|||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.baeldung.web.service.AsyncService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
@ -9,29 +10,30 @@ import org.springframework.stereotype.Controller;
|
|||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@Controller
|
||||
public class AsyncController {
|
||||
|
||||
private static final Logger log = Logger.getLogger(AsyncService.class);
|
||||
|
||||
@Autowired
|
||||
private AsyncService asyncService;
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST, value = "/upload")
|
||||
public Callable<Boolean> processUpload(final MultipartFile file) {
|
||||
|
||||
return new Callable<Boolean>() {
|
||||
public Boolean call() throws Exception {
|
||||
// ...
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/async")
|
||||
@ResponseBody
|
||||
public Boolean checkIfContextPropagated() throws Exception{
|
||||
return asyncService.checkIfPrincipalPropagated().call() && asyncService.checkIfContextPropagated(SecurityContextHolder.getContext());
|
||||
public Object standardProcessing() throws Exception {
|
||||
log.info("Outside the @Async logic - before the async call: "
|
||||
+ SecurityContextHolder.getContext().getAuthentication().getPrincipal());
|
||||
asyncService.asyncCall();
|
||||
log.info("Inside the @Async logic - after the async call: "
|
||||
+ SecurityContextHolder.getContext().getAuthentication().getPrincipal());
|
||||
return SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/async2")
|
||||
@ResponseBody
|
||||
public Callable<Boolean> springMVCAsyncTest() {
|
||||
return asyncService.checkIfPrincipalPropagated();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ import java.util.concurrent.Callable;
|
|||
|
||||
public interface AsyncService {
|
||||
|
||||
void asyncCall();
|
||||
|
||||
Callable<Boolean> checkIfPrincipalPropagated();
|
||||
|
||||
Boolean checkIfContextPropagated(Object context);
|
||||
|
||||
}
|
||||
|
|
|
@ -12,25 +12,25 @@ public class AsyncServiceImpl implements AsyncService {
|
|||
|
||||
private static final Logger log = Logger.getLogger(AsyncService.class);
|
||||
|
||||
@Override
|
||||
public Callable<Boolean> checkIfPrincipalPropagated() {
|
||||
Object before = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
log.info("Before new thread: " + before);
|
||||
return new Callable<Boolean>() {
|
||||
public Boolean call() throws Exception {
|
||||
Object after = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
log.info("New thread: " + after);
|
||||
return before == after;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Async
|
||||
@Override
|
||||
public Boolean checkIfContextPropagated(Object context) {
|
||||
log.info("Before @Async: " + context);
|
||||
log.info("Inside @Async: " + SecurityContextHolder.getContext());
|
||||
return context == SecurityContextHolder.getContext();
|
||||
public void asyncCall() {
|
||||
log.info("Inside the @Async logic: " + SecurityContextHolder.getContext().getAuthentication().getPrincipal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callable<Boolean> checkIfPrincipalPropagated() {
|
||||
Object before
|
||||
= SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
log.info("Before new thread: " + before);
|
||||
|
||||
return new Callable<Boolean>() {
|
||||
public Boolean call() throws Exception {
|
||||
Object after
|
||||
= SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
log.info("New thread: " + after);
|
||||
return before == after;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,9 +34,4 @@
|
|||
</authentication-provider>
|
||||
</authentication-manager>
|
||||
|
||||
<beans:bean
|
||||
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
|
||||
p:targetClass="org.springframework.security.core.context.SecurityContextHolder"
|
||||
p:targetMethod="setStrategyName" p:arguments="MODE_INHERITABLETHREADLOCAL" />
|
||||
|
||||
</beans:beans>
|
|
@ -32,6 +32,7 @@
|
|||
<param-name>throwExceptionIfNoHandlerFound</param-name>
|
||||
<param-value>true</param-value>
|
||||
</init-param>
|
||||
<async-supported>true</async-supported>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>api</servlet-name>
|
||||
|
@ -42,12 +43,13 @@
|
|||
<filter>
|
||||
<filter-name>springSecurityFilterChain</filter-name>
|
||||
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
|
||||
<async-supported>true</async-supported>
|
||||
</filter>
|
||||
<filter-mapping>
|
||||
<filter-name>springSecurityFilterChain</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
<dispatcher>REQUEST</dispatcher>
|
||||
<dispatcher>ASYNC</dispatcher>
|
||||
<dispatcher>ASYNC</dispatcher>
|
||||
</filter-mapping>
|
||||
|
||||
<!-- <welcome-file-list> -->
|
||||
|
|
|
@ -12,7 +12,6 @@ import org.junit.runner.RunWith;
|
|||
import org.mockito.Mock;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.mock.web.MockHttpSession;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
|
@ -42,10 +41,8 @@ public class AsyncControllerTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testProcessUpload() throws Exception {
|
||||
MockMultipartFile jsonFile = new MockMultipartFile("json", "", "application/json",
|
||||
"{\"json\": \"someValue\"}".getBytes());
|
||||
mockMvc.perform(MockMvcRequestBuilders.fileUpload("/upload").file(jsonFile)).andExpect(status().isOk());
|
||||
public void testAsync() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/async")).andExpect(status().is5xxServerError());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue