配置 Spring 安全性时遇到问题
Having Trouble Configuring Spring Security
我正在尝试使用 Spring 的 Java 配置和注释通过 CXF REST 应用程序配置 Spring 安全性。
我的 WebApplicationInitializer 包含
public class WebAppInitializer implements WebApplicationInitializer {
@Override
public void onStartup (ServletContext container) {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(AppConfig.class);
container.addListener(new ContextLoaderListener(context));
context.refresh();
ServletRegistration.Dynamic cxf = container.addServlet("CXFServlet",new
CXFServlet());
cxf.addMapping("/api/*");
cxf.setLoadOnStartup(1);
} //onStartup
}
应用配置:
@Configuration
@ComponentScan(basePackages="com.anodyzed.vyta",excludeFilters={
@ComponentScan.Filter(type=FilterType.ANNOTATION,value=Repository.class)
})
@Import({PersistenceConfig.class,RestConfig.class})
@ImportResource({/*"classpath:applicationContext.xml",*/"classpath:META-INF/cxf/cxf.xml","classpath:META-INF/cxf/cxf-servlet.xml"})
public class AppConfig {
@Bean
public CustomerResource customerResource () {
return new CustomerResource();
} //CustomerResource
} //*AppConfig
安全配置如下所示:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled=true)
public class SecurityConfigAdapter extends WebSecurityConfigurerAdapter {
@Override
public void configure (AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
auth.inMemoryAuthentication()
.withUser("bob").password(encoder.encode("bobpassword"))
.roles("USER")
.and()
.withUser("fred").password(encoder.encode("fredpassword"))
.roles("ADMIN","USER");
} //configure
@Override
protected void configure (HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/**").authenticated()
.and().httpBasic()
.and().csrf().disable();
} //configure
} //*SecurityConfigAdapter
以及资源本身:
@Path("/customer")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class CustomerResource {
@Autowired
private CustomerService customerService;
@GET
@Path("/{id}")
@Secured({"ROLE_USER","ROLE_ADMIN"})
public Customer read (@PathParam("id") long id) {
return customerService.read(id);
} //read
} //*CustomerResource
当我点击 {{server}}/app/api/customer/123(使用 PostMan)时,它 returns 401 Unauthorized。日志显示:
[2018-12-09 21:43:33,307] {resin-port-80-17} DEBUG org.springframework.security.web.FilterChainProxy - /api/customer/123 at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
[2018-12-09 21:43:33,321] {resin-port-80-17} DEBUG org.springframework.security.web.FilterChainProxy - /api/customer/123 at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
[2018-12-09 21:43:33,330] {resin-port-80-17} DEBUG org.springframework.security.web.context.HttpSessionSecurityContextRepository - No HttpSession currently exists
[2018-12-09 21:43:33,330] {resin-port-80-17} DEBUG org.springframework.security.web.context.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: null. A new one will be created.
[2018-12-09 21:43:33,334] {resin-port-80-17} DEBUG org.springframework.security.web.FilterChainProxy - /api/customer/123 at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.FilterChainProxy - /api/customer/123 at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.util.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/logout', GET]
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/api/customer/123'; against '/logout'
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.util.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/logout', POST]
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'GET /api/customer/123' doesn't match 'POST /logout
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.util.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/logout', PUT]
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'GET /api/customer/123' doesn't match 'PUT /logout
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.util.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/logout', DELETE]
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'GET /api/customer/123' doesn't match 'DELETE /logout
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.util.matcher.OrRequestMatcher - No matches found
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.FilterChainProxy - /api/customer/123 at position 5 of 11 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
[2018-12-09 21:43:33,336] {resin-port-80-17} DEBUG org.springframework.security.web.authentication.www.BasicAuthenticationFilter - Basic Authentication Authorization header found for user 'bob'
[2018-12-09 21:43:33,337] {resin-port-80-17} DEBUG org.springframework.security.authentication.ProviderManager - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
[2018-12-09 21:43:33,491] {resin-port-80-17} DEBUG org.springframework.security.authentication.dao.DaoAuthenticationProvider - Authentication failed: password does not match stored value
[2018-12-09 21:43:33,491] {resin-port-80-17} DEBUG org.springframework.security.web.authentication.www.BasicAuthenticationFilter - Authentication request for failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
[2018-12-09 21:43:33,491] {resin-port-80-17} DEBUG org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint - Trying to match using RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]
[2018-12-09 21:43:33,491] {resin-port-80-17} DEBUG org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint - No match found. Using default entry point org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint@1b289b8d
[2018-12-09 21:43:33,492] {resin-port-80-17} DEBUG org.springframework.security.web.header.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@35870e55
[2018-12-09 21:43:33,492] {resin-port-80-17} DEBUG org.springframework.security.web.context.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
[2018-12-09 21:43:33,495] {resin-port-80-17} DEBUG org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
如能指出我做错的地方,将不胜感激。
对于基本请求,您应该将{username:password} base64encode 到header。
对于用户 bob/bobpassword(base64 在线 here)
base64encode{bob:bobpassword} --> Ym9iOmJvYnBhc3N3b3Jk
然后就可以在授权header中发送一个带有basic Ym9iOmJvYnBhc3N3b3Jk
的请求了。
我正在尝试使用 Spring 的 Java 配置和注释通过 CXF REST 应用程序配置 Spring 安全性。
我的 WebApplicationInitializer 包含
public class WebAppInitializer implements WebApplicationInitializer {
@Override
public void onStartup (ServletContext container) {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(AppConfig.class);
container.addListener(new ContextLoaderListener(context));
context.refresh();
ServletRegistration.Dynamic cxf = container.addServlet("CXFServlet",new
CXFServlet());
cxf.addMapping("/api/*");
cxf.setLoadOnStartup(1);
} //onStartup
}
应用配置:
@Configuration
@ComponentScan(basePackages="com.anodyzed.vyta",excludeFilters={
@ComponentScan.Filter(type=FilterType.ANNOTATION,value=Repository.class)
})
@Import({PersistenceConfig.class,RestConfig.class})
@ImportResource({/*"classpath:applicationContext.xml",*/"classpath:META-INF/cxf/cxf.xml","classpath:META-INF/cxf/cxf-servlet.xml"})
public class AppConfig {
@Bean
public CustomerResource customerResource () {
return new CustomerResource();
} //CustomerResource
} //*AppConfig
安全配置如下所示:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled=true)
public class SecurityConfigAdapter extends WebSecurityConfigurerAdapter {
@Override
public void configure (AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
auth.inMemoryAuthentication()
.withUser("bob").password(encoder.encode("bobpassword"))
.roles("USER")
.and()
.withUser("fred").password(encoder.encode("fredpassword"))
.roles("ADMIN","USER");
} //configure
@Override
protected void configure (HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/**").authenticated()
.and().httpBasic()
.and().csrf().disable();
} //configure
} //*SecurityConfigAdapter
以及资源本身:
@Path("/customer")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class CustomerResource {
@Autowired
private CustomerService customerService;
@GET
@Path("/{id}")
@Secured({"ROLE_USER","ROLE_ADMIN"})
public Customer read (@PathParam("id") long id) {
return customerService.read(id);
} //read
} //*CustomerResource
当我点击 {{server}}/app/api/customer/123(使用 PostMan)时,它 returns 401 Unauthorized。日志显示:
[2018-12-09 21:43:33,307] {resin-port-80-17} DEBUG org.springframework.security.web.FilterChainProxy - /api/customer/123 at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
[2018-12-09 21:43:33,321] {resin-port-80-17} DEBUG org.springframework.security.web.FilterChainProxy - /api/customer/123 at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
[2018-12-09 21:43:33,330] {resin-port-80-17} DEBUG org.springframework.security.web.context.HttpSessionSecurityContextRepository - No HttpSession currently exists
[2018-12-09 21:43:33,330] {resin-port-80-17} DEBUG org.springframework.security.web.context.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: null. A new one will be created.
[2018-12-09 21:43:33,334] {resin-port-80-17} DEBUG org.springframework.security.web.FilterChainProxy - /api/customer/123 at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.FilterChainProxy - /api/customer/123 at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.util.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/logout', GET]
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/api/customer/123'; against '/logout'
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.util.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/logout', POST]
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'GET /api/customer/123' doesn't match 'POST /logout
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.util.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/logout', PUT]
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'GET /api/customer/123' doesn't match 'PUT /logout
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.util.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/logout', DELETE]
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'GET /api/customer/123' doesn't match 'DELETE /logout
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.util.matcher.OrRequestMatcher - No matches found
[2018-12-09 21:43:33,335] {resin-port-80-17} DEBUG org.springframework.security.web.FilterChainProxy - /api/customer/123 at position 5 of 11 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
[2018-12-09 21:43:33,336] {resin-port-80-17} DEBUG org.springframework.security.web.authentication.www.BasicAuthenticationFilter - Basic Authentication Authorization header found for user 'bob'
[2018-12-09 21:43:33,337] {resin-port-80-17} DEBUG org.springframework.security.authentication.ProviderManager - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
[2018-12-09 21:43:33,491] {resin-port-80-17} DEBUG org.springframework.security.authentication.dao.DaoAuthenticationProvider - Authentication failed: password does not match stored value
[2018-12-09 21:43:33,491] {resin-port-80-17} DEBUG org.springframework.security.web.authentication.www.BasicAuthenticationFilter - Authentication request for failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
[2018-12-09 21:43:33,491] {resin-port-80-17} DEBUG org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint - Trying to match using RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]
[2018-12-09 21:43:33,491] {resin-port-80-17} DEBUG org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint - No match found. Using default entry point org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint@1b289b8d
[2018-12-09 21:43:33,492] {resin-port-80-17} DEBUG org.springframework.security.web.header.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@35870e55
[2018-12-09 21:43:33,492] {resin-port-80-17} DEBUG org.springframework.security.web.context.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
[2018-12-09 21:43:33,495] {resin-port-80-17} DEBUG org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
如能指出我做错的地方,将不胜感激。
对于基本请求,您应该将{username:password} base64encode 到header。 对于用户 bob/bobpassword(base64 在线 here)
base64encode{bob:bobpassword} --> Ym9iOmJvYnBhc3N3b3Jk
然后就可以在授权header中发送一个带有basic Ym9iOmJvYnBhc3N3b3Jk
的请求了。