我是spring-security的新手,我需要设置一个授权系统来保护REST服务。
就我而言,我的“用户”是不同部门和公司的一些服务器。所以我尝试将服务器配置为MyUser,这是UserDetails的子类。
但是当我被要求授权服务器的IP地址时,我遇到了一个问题。我在WebSecurityConfigurerAdapter.configure(HttpSecurity http)中看到了ip地址授权,我可以使用configure(AuthenticationManagerBuilder auth){auth.userDetailsService(myUserDetailsService);}检索配置。但似乎configure(HttpSecurity http)方法仅在系统启动时运行一次。
那么,我该怎么办?有没有办法添加自定义检查器或其他东西来验证IP地址?
这些是我的代码:
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.httpBasic().and()
.authorizeRequests()
.antMatchers("/order/**").hasAuthority("read_order") //(1)
.antMatchers("/order/**").hasIpAddress("192.168.1.45") //(2)
.anyRequest().denyAll();
// @formatter:on
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
}
使用实现userService
的自定义UserDetailsService
,我可以用数据库中的配置替换(1)行。这意味着当我更改配置时,Spring Security将从数据库加载它。我不需要重新启动系统。
我如何对(2)行做类似的事情?
答案 0 :(得分:0)
我找到了解决方案。我不确定它是最好的方式,但它可以工作。这是解决方案。
首先,我们可以定义一个实现AccessDecisionManager的类:
@Service
public class ResourceAccessDecisionManager implements AccessDecisionManager {
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
throws
AccessDeniedException, InsufficientAuthenticationException {
//...
HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
String ip = request.getRemoteHost();
Object principal = authentication.getPrincipal();
User user;
if (principal instanceof User){
user=(User)principal;
if (!ip.equals(user.getIpConfig())){
throw new AccessDeniedException("wrong ip");
}
}
//...
}
//...
}
当然,您必须在User类中存储ip配置。 然后,我们定义一个类,扩展AbstractSecurityInterceptor实现Filter:
@Service
public class ResourceFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
//...
@Autowired
public void setMyAccessDecisionManager(ResourceAccessDecisionManager resourceAccessDecisionManager) {
super.setAccessDecisionManager(resourceAccessDecisionManager);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(servletRequest, servletResponse, filterChain);
invoke(fi);
}
private void invoke(FilterInvocation fi) throws IOException, ServletException {
InterceptorStatusToken token = super.beforeInvocation(fi);
try {
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} finally {
super.afterInvocation(token, null);
}
}
//...
}
将过滤器添加到安全配置类:
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final ResourceService resourceService;
private final UserService userService;
private final HttpServletRequest request;
private final ResourceFilterSecurityInterceptor resourceFilterSecurityInterceptor;
private final EnvironmentConfig environmentConfig;
@Autowired
public SecurityConfiguration(ResourceService resourceService, UserService userService,
HttpServletRequest request,
ResourceFilterSecurityInterceptor resourceFilterSecurityInterceptor,
EnvironmentConfig environmentConfig) {
this.resourceService = resourceService;
this.userService = userService;
this.request = request;
this.resourceFilterSecurityInterceptor = resourceFilterSecurityInterceptor;
this.environmentConfig = environmentConfig;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.httpBasic().and()
.authorizeRequests()
.antMatchers("/order/**").authenticated()
.anyRequest().authenticated()
.and().csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
;
http.addFilterBefore(resourceFilterSecurityInterceptor,FilterSecurityInterceptor.class);
// @formatter:on
}
//...
}
现在它可以工作,但任何建议都是受欢迎的,并且令人钦佩,以改善解决方案。