2017-12-10 3 views
9

私のSpringブートアプリケーションでは、/api/**にエンドポイントの束があります。以下は、私のアプリの設定です:エンドポイントへのAPIコールとブラウザ訪問者を区別するSpring

/api/**の背後にあるエンドポイントへのアクセスは、私何がされていない、私はブラウザで /api/my_endpointに入力すると、したがって、私は戻ってエラーを取得し、認証されるようにチェックされている
@Configuration 
public class AppConfig extends WebMvcConfigurerAdapter { 

    private class PushStateResourceResolver implements ResourceResolver { 
     private Resource index = new ClassPathResource("/public/index.html"); 
     private List<String> handledExtensions = Arrays.asList("html", "js", 
       "json", "csv", "css", "png", "svg", "eot", "ttf", "woff", 
       "appcache", "jpg", "jpeg", "gif", "ico"); 

     private List<String> ignoredPaths = Arrays.asList("^api\\/.*$"); 

     @Override 
     public Resource resolveResource(HttpServletRequest request, 
       String requestPath, List<? extends Resource> locations, 
       ResourceResolverChain chain) { 
      return resolve(requestPath, locations); 
     } 

     @Override 
     public String resolveUrlPath(String resourcePath, 
       List<? extends Resource> locations, ResourceResolverChain chain) { 
      Resource resolvedResource = resolve(resourcePath, locations); 
      if (resolvedResource == null) { 
       return null; 
      } 
      try { 
       return resolvedResource.getURL().toString(); 
      } catch (IOException e) { 
       return resolvedResource.getFilename(); 
      } 
     } 

     private Resource resolve(String requestPath, 
       List<? extends Resource> locations) { 
      if (isIgnored(requestPath)) { 
       return null; 
      } 
      if (isHandled(requestPath)) { 
       return locations 
         .stream() 
         .map(loc -> createRelative(loc, requestPath)) 
         .filter(resource -> resource != null 
           && resource.exists()).findFirst() 
         .orElseGet(null); 
      } 
      return index; 
     } 

     private Resource createRelative(Resource resource, String relativePath) { 
      try { 
       return resource.createRelative(relativePath); 
      } catch (IOException e) { 
       return null; 
      } 
     } 

     private boolean isIgnored(String path) { 
      return false; 
      //   return !ignoredPaths.stream().noneMatch(rgx -> Pattern.matches(rgx, path)); 
      //deliberately made this change for examining the code 
     } 

     private boolean isHandled(String path) { 
      String extension = StringUtils.getFilenameExtension(path); 
      return handledExtensions.stream().anyMatch(
        ext -> ext.equals(extension)); 
     } 
    } 
} 

欲しいです。ユーザーにindex.htmlを提供してもらいたい

+1

すべてのリクエストに対してインターセプタまたはフィルタを使用し、レスポンスとパスを確認して、適切に動作させることはできますか? – DvTr

答えて

2

だから、私は最終的に私のセキュリティ設定を固定することにより、この問題を解決しました失敗した場合、私はユーザーを "/"にリダイレクトします。返信先はリソースリゾルバによって取得され、index.htmlが配信されます。

+0

あなたの問題を解決してよかった。次回より詳細情報をお知らせください。カスタム認証フィルタを使用していることを確認します。 – Christian

1

ブラウザは通常、http要求の「User-Agent」ヘッダーを設定します。

したがって、これらの呼び出しを区別することができます:request.getHeader( "User-Agent");

も参照してください:あなたはX-Requested-Withヘッダを確認することができ

2

private boolean isAjax(HttpServletRequest request) { 
    String requestedWithHeader = request.getHeader("X-Requested-With"); 
    return "XMLHttpRequest".equals(requestedWithHeader); 
} 

がUPDATE:たぶんそれはへのより良いアプローチですAcceptヘッダーを確認します。ブラウザがAccept: text/htmlヘッダーをスクリプトなどに含めると、X-Requested-Withヘッダーが含まれている可能性がはるかに高いと思います。

Accept: text/htmlヘッダが存在する場合は、カスタム認証エントリポイントを作成し、ユーザーをリダイレクトすることができます:

public class CustomEntryPoint implements AuthenticationEntryPoint { 

    private static final String ACCEPT_HEADER = "Accept"; 

    private final RedirectStrategy redirect = new DefaultRedirectStrategy(); 

    @Override 
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) 
      throws IOException, ServletException { 
     if (isHtmlRequest(request)) { 
      redirect.sendRedirect(request, response, "/"); 
     } else { 
      response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized access is not allowed"); 
     } 
    } 

    private boolean isHtmlRequest(HttpServletRequest request) { 
     String acceptHeader = request.getHeader(ACCEPT_HEADER); 
     List<MediaType> acceptedMediaTypes = MediaType.parseMediaTypes(acceptHeader); 
     return acceptedMediaTypes.contains(MediaType.TEXT_HTML); 
    } 

} 

注:

をあなたが(AbstractAuthenticationProcessingFilterから継承)カスタム認証フィルタを使用する場合認証エントリポイントは呼び出されません。 unsuccessfulAuthentication()メソッドのリダイレクトはAbstractAuthenticationProcessingFilterです。

代替:春ブーツの

  • オーバーライド標準BasicErrorControllerとそこ401 Unauthorizedエラーのリダイレクトを処理します。
  • /apiの呼び出しとhtmlのすべてでJSONを返さないのはなぜですか?認証た場合、あなたが見ることができるように

    @Override 
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException { 
        logger.debug("failed authentication while attempting to access "+ URL_PATH_HELPER.getPathWithinApplication((HttpServletRequest) request)); 
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); 
        response.sendRedirect("/"); 
    } 
    

    :私はunsuccessfulAuthenticationメソッドをオーバーライドするカスタムJWTAuthenticationFilterを持って

関連する問題