73015


### 状況①

以下のようなディレクトリが存在します。

[code]

    C
    └work
    　└pic
    　　├pic1.jpg
    　　├pic2.jpg
    　　└pic3.jpg
    
[/code]

### 状況②

以下のようなソースコードを書くことで以下のフロントエンド側のディレクトリ `http://localhost:8080/data/pic`
配下の画像リソースにアクセスできるようになります。

[code]

    @Configuration
    public class WebMvcConfig implements WebMvcConfigurer {
    
        private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
                "classpath:/META-INF/resources/", "classpath:/resources/",
                "classpath:/static/", "classpath:/public/", "classpath:/custom/"
        };
    
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/**").addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS)
                    .resourceChain(true)
                    .addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
                registry.addResourceHandler("/data/pic/**").addResourceLocations("file:///C:\\work\pic\\");
    
        }
    
    
        @Bean
        public ResourceUrlEncodingFilter resourceUrlEncodingFilter() {
            return new ResourceUrlEncodingFilter();
        }
    
[/code]

### 問題点

ユーザー1はpic1.jpgのみ閲覧可能、ユーザー2はpic2.jpgのみ閲覧可能、と制限をかけるにはどうしたら良いか思いつく人はいらっしゃらないでしょうか？  
現状URLを直接入力した場合以下の全ての画像が閲覧可能となっています。

[code]

    http://localhost:8080/data/pic/pic1.jpg
    http://localhost:8080/data/pic/pic2.jpg
    http://localhost:8080/data/pic/pic3.jpg
    
[/code]


CC BY-SA 4.0
2020-12-31T19:36:03.977
73000
2021-01-01T23:25:05.413
2021-01-01T05:49:30.313
3060
43357
question
java spring-boot thymeleaf spring-security
サーバーサイドから取得した静的リソースをユーザーごとにアクセス制限をかけたい


認証情報を参照して、リクエストされたパスにアクセス可能かどうかを検証するフィルタを実装することで実現できるかと考えます。

[code]

    @Component
    public class MyPicAccessRestrictionFilter extends OncePerRequestFilter {
    
        private static final Map<String, String> ALLOW_LIST = Map.of(
            "/data/pic/pic1.jpg", "user1",
            "/data/pic/pic2.jpg", "user2",
            "/data/pic/pic3.jpg", "user3");
    
        @Override
        protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response,
            final FilterChain filterChain)
            throws ServletException, IOException {
    
            final SecurityContext ctx = SecurityContextHolder.getContext();
            final Authentication authn = ctx.getAuthentication();
            if (authn == null) {
                response.sendError(HttpStatus.UNAUTHORIZED.value());
                return;
            }
            final String name = authn.getName();
    
            final String path = request.getServletPath();
            final String allowedUser = ALLOW_LIST.get(path);
    
            if (!Objects.equals(name, allowedUser)) {
                response.sendError(HttpStatus.FORBIDDEN.value(), name + "には権限がありません");
                return;
            }
    
            filterChain.doFilter(request, response);
        }
    
    }
    
[/code]

[code]

        // フィルタ追加
        // https://docs.spring.io/spring-boot/docs/2.4.1/reference/html/howto.html#howto-add-a-servlet-filter-or-listener
        @Bean
        public FilterRegistrationBean<MyPicAccessRestrictionFilter> registration(
            final MyPicAccessRestrictionFilter filter) {
            final FilterRegistrationBean<MyPicAccessRestrictionFilter> registration = new FilterRegistrationBean<>(filter);
            registration.setUrlPatterns(List.of("/data/pic/*"));
            // 認証フィルタより優先度を下げる必要がある
            registration.setOrder(Ordered.LOWEST_PRECEDENCE);
            return registration;
        }
    
[/code]

[サンプルコード](https://github.com/yukihane/stackoverflow-qa/tree/master/jaso73000)


CC BY-SA 4.0
2021-01-01T23:25:05.413
73015
2021-01-01T23:25:05.413
2808
73000
answer