前言
场景:对磁盘上的视频文件访问进行控制,因为视频可能包含敏感信息,所以不能让任何人都能随意访问。
思路
-
访问视频
视频文件存在专门磁盘目录下,如何让视频能被访问到?在
SpringBoot中可以配置虚拟路径映射,使用ResourceHandlerRegistry将本地磁盘路径映射成url来实现。 -
访问控制
使用
Filter做访问控制,对上述映射出来的url进行拦截并校验访问权限。
实现
访问视频
-
定义配置
video-access: enable: true # url不以 / 结束 url: /video # location以 / 结束 location: G:/tmp/video-access/ # ip 白名单 whiteList: - 192.168.*.* # ip 黑名单 blackList:@Data @ConfigurationProperties(prefix = "video-access") @Component public class VideoAccessConfig { // 是否开启访问校验 private boolean enable = true; // 映射url private String url = ""; // 视频文件路径 private String location = ""; // ip白名单 private Set<String> whiteList = new HashSet<>(8); // ip黑名单 private Set<String> blackList = new HashSet<>(8); public Set<String> getWhiteList() { // 本地默认添加到白名单 whiteList.add("127.0.0.1"); whiteList.add("0:0:0:0:0:0:0:1"); return whiteList; } } -
添加映射
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Autowired private VideoAccessConfig videoAccessConfig; @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(videoAccessConfig.getUrl() + "/**") .addResourceLocations("file:" + videoAccessConfig.getLocation()); } }
访问控制
-
访问机制
ip是否在白名单中whiteList,在跳过ip是否在黑名单中blackList,在拒绝- 自定义访问控制逻辑
-
定义
Filter@Component public class VideoAccessFilter extends OncePerRequestFilter { @Autowired private VideoAccessConfig videoAccessConfig; private AntPathMatcher antPathMatcher = new AntPathMatcher(); @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 此处获取ip简单处理;可通过请求头获取真实ip String ip = request.getRemoteAddr(); // 白名单放行 Set<String> whiteList = accessControlConfig.getWhiteList(); boolean ignored = whiteList.stream().anyMatch(item -> antPathMatcher.match(item, ip)); if (ignored) { filterChain.doFilter(request, response); return; } // 黑名单拦截 Set<String> blackList = accessControlConfig.getBlackList(); boolean blocked = blackList.stream().anyMatch(item -> antPathMatcher.match(item, ip)); if (blocked) { reject(response); return; } // TODO:此处自定义访问控制逻辑 String token = httpServletRequest.getQueryString(); if (videoAccessConfig.isEnable() && Objects.isNull(token)) { reject(response); return; } filterChain.doFilter(request, response); } private void reject(HttpServletResponse response) throws IOException { response.setStatus(HttpServletResponse.SC_FORBIDDEN); response.getOutputStream().write("Access Denied".getBytes(StandardCharsets.UTF_8)); response.getOutputStream().close(); } } -
拦截
url,使用FilterRegistrationBean注册Filter@Autowired private VideoAccessFilter videoAccessFilter; @Bean public FilterRegistrationBean filterOneRegister() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>(); filterRegistrationBean.setFilter(videoAccessFilter); filterRegistrationBean.addUrlPatterns(videoAccessConfig.getUrl() + "/*"); return filterRegistrationBean; }
测试
映射图片路径方便测试,测试url含queryString表示有权限
- 映射文件夹
- 无权限
http://localhost:8080/video/miruiki.jpg
- 有权限
http://localhost:8080/video/miruiki.jpg?token=1231
结尾
如果文章对你有帮助,请点 赞👍🏻 支持一下。若有错误之处或有更好的建议,欢迎指正,谢谢。