How can I prevent the Angular 6 Custom-Reuse-Strategy from caching a 403 forbidden page?












0















Hope someone can guide me on this issue.



Coding an Angular 6 application, I am using the Custom-Reuse-Strategy to cache pages the user has been to and also a HttpInterceptor to handle 401/403 type
requests.



My issue is when this set of conditions apply:




  1. The user clicks on say a link that goes to /blogs

  2. The http request is made to my dotnet webapi controller which checks the users roles e.g. "Author". The controller identifies this user as not having the "Author" role so it returns back a 403 (forbidden) status code.

  3. The interceptor component picks up on this 403 status and redirects the user to a "forbidden" page.


This all works fine, however



Even though the interceptor is picking up on the 403 and doing a redirect, the reuse strategy component still caches the /blogs page into it's array of cached pages. So, when the user clicks the link to go to the /blogs route again, the cache kicks in and provides the page to the user and as no http request is made this time due to it being pulled from the reuse cache, the 403 forbidden is not picked up in the interceptor so the user is shown a half rendered /blogs page (with no data as the webapi didn't return any).



Is there a way for me to prevent that /blogs page being placed into the reuse cache when it is on a 403 forbidden status?



I have tried to look inside the reuse cache just before I redirect to the forbidden page in the interceptor but at that point the cache does not have the /blogs item. It must be being added after the interceptor has completed it's work.



I understand the link can be hidden if the user does not have the role but for arguments sake, let's say the link is visible even without the correct role.



So, can I prevent it going in the cache or can I remove it from the cache somehow based on the interceptor.



Hope someone can advise.



Thanks.



custom-reuse-strategy.ts




import { RouteReuseStrategy, DetachedRouteHandle, ActivatedRouteSnapshot } from "@angular/router";
import { SignInComponent } from "./user/sign-in/sign-in.component";


export class CustomReuseStrategy implements RouteReuseStrategy {

private handlers: {[key: string]: DetachedRouteHandle} = {};

private cachedUrls = [
/home/
]

constructor() {}

shouldDetach(route: ActivatedRouteSnapshot): boolean {
return true;
}

store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
let url = route.url.join("/") || route.parent.url.join("/");
//Don't cache the following urls...
if(url.startsWith('member/view/') || url.startsWith('post/') || url === "home"){
return;
}
this.handlers[url] = handle;
}

shouldAttach(route: ActivatedRouteSnapshot): boolean {
let url = route.url.join("/") || route.parent.url.join("/");
//Logout - remove all cached routes
if (route.component == SignInComponent) {
this.handlers = {};
return false;
}

//If this route is cached - load up the cached information
for (let preservedUrl of this.cachedUrls) {
if (preservedUrl.test(url)) {
return false;
}
}
return !!this.handlers[url];
}

retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
return this.handlers[route.url.join("/") || route.parent.url.join("/")];
}

shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}


}


auth.interceptor.ts





import { HttpInterceptor, HttpRequest, HttpHandler, HttpUserEvent, HttpEvent } from "@angular/common/http";
import { Observable } from "rxjs";
import { tap } from 'rxjs/operators';
import { Injectable } from "@angular/core";
import { Router } from "@angular/router";


@Injectable()
export class AuthInterceptor implements HttpInterceptor {

constructor(private router: Router) { }

intercept(req: HttpRequest, next: HttpHandler): Observable> {
if (req.headers.get('No-Auth') == "True")
{
return next.handle(req.clone());
}

if (localStorage.getItem('userToken') != null) {
const clonedreq = req.clone({
headers: req.headers.set("Authorization", "Bearer " + localStorage.getItem('userToken'))
});

return next.handle(clonedreq).pipe
(
tap(
succ => { },
err => {
if (err.status === 401){
localStorage.removeItem('userToken');
this.router.navigateByUrl('/account/login');
}
else if (err.status === 403){
this.router.navigateByUrl('/forbidden');
}
}
)
);
}
else {
this.router.navigateByUrl('/account/login');
}
}
}










share|improve this question





























    0















    Hope someone can guide me on this issue.



    Coding an Angular 6 application, I am using the Custom-Reuse-Strategy to cache pages the user has been to and also a HttpInterceptor to handle 401/403 type
    requests.



    My issue is when this set of conditions apply:




    1. The user clicks on say a link that goes to /blogs

    2. The http request is made to my dotnet webapi controller which checks the users roles e.g. "Author". The controller identifies this user as not having the "Author" role so it returns back a 403 (forbidden) status code.

    3. The interceptor component picks up on this 403 status and redirects the user to a "forbidden" page.


    This all works fine, however



    Even though the interceptor is picking up on the 403 and doing a redirect, the reuse strategy component still caches the /blogs page into it's array of cached pages. So, when the user clicks the link to go to the /blogs route again, the cache kicks in and provides the page to the user and as no http request is made this time due to it being pulled from the reuse cache, the 403 forbidden is not picked up in the interceptor so the user is shown a half rendered /blogs page (with no data as the webapi didn't return any).



    Is there a way for me to prevent that /blogs page being placed into the reuse cache when it is on a 403 forbidden status?



    I have tried to look inside the reuse cache just before I redirect to the forbidden page in the interceptor but at that point the cache does not have the /blogs item. It must be being added after the interceptor has completed it's work.



    I understand the link can be hidden if the user does not have the role but for arguments sake, let's say the link is visible even without the correct role.



    So, can I prevent it going in the cache or can I remove it from the cache somehow based on the interceptor.



    Hope someone can advise.



    Thanks.



    custom-reuse-strategy.ts




    import { RouteReuseStrategy, DetachedRouteHandle, ActivatedRouteSnapshot } from "@angular/router";
    import { SignInComponent } from "./user/sign-in/sign-in.component";


    export class CustomReuseStrategy implements RouteReuseStrategy {

    private handlers: {[key: string]: DetachedRouteHandle} = {};

    private cachedUrls = [
    /home/
    ]

    constructor() {}

    shouldDetach(route: ActivatedRouteSnapshot): boolean {
    return true;
    }

    store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
    let url = route.url.join("/") || route.parent.url.join("/");
    //Don't cache the following urls...
    if(url.startsWith('member/view/') || url.startsWith('post/') || url === "home"){
    return;
    }
    this.handlers[url] = handle;
    }

    shouldAttach(route: ActivatedRouteSnapshot): boolean {
    let url = route.url.join("/") || route.parent.url.join("/");
    //Logout - remove all cached routes
    if (route.component == SignInComponent) {
    this.handlers = {};
    return false;
    }

    //If this route is cached - load up the cached information
    for (let preservedUrl of this.cachedUrls) {
    if (preservedUrl.test(url)) {
    return false;
    }
    }
    return !!this.handlers[url];
    }

    retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
    return this.handlers[route.url.join("/") || route.parent.url.join("/")];
    }

    shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    return future.routeConfig === curr.routeConfig;
    }


    }


    auth.interceptor.ts





    import { HttpInterceptor, HttpRequest, HttpHandler, HttpUserEvent, HttpEvent } from "@angular/common/http";
    import { Observable } from "rxjs";
    import { tap } from 'rxjs/operators';
    import { Injectable } from "@angular/core";
    import { Router } from "@angular/router";


    @Injectable()
    export class AuthInterceptor implements HttpInterceptor {

    constructor(private router: Router) { }

    intercept(req: HttpRequest, next: HttpHandler): Observable> {
    if (req.headers.get('No-Auth') == "True")
    {
    return next.handle(req.clone());
    }

    if (localStorage.getItem('userToken') != null) {
    const clonedreq = req.clone({
    headers: req.headers.set("Authorization", "Bearer " + localStorage.getItem('userToken'))
    });

    return next.handle(clonedreq).pipe
    (
    tap(
    succ => { },
    err => {
    if (err.status === 401){
    localStorage.removeItem('userToken');
    this.router.navigateByUrl('/account/login');
    }
    else if (err.status === 403){
    this.router.navigateByUrl('/forbidden');
    }
    }
    )
    );
    }
    else {
    this.router.navigateByUrl('/account/login');
    }
    }
    }










    share|improve this question



























      0












      0








      0








      Hope someone can guide me on this issue.



      Coding an Angular 6 application, I am using the Custom-Reuse-Strategy to cache pages the user has been to and also a HttpInterceptor to handle 401/403 type
      requests.



      My issue is when this set of conditions apply:




      1. The user clicks on say a link that goes to /blogs

      2. The http request is made to my dotnet webapi controller which checks the users roles e.g. "Author". The controller identifies this user as not having the "Author" role so it returns back a 403 (forbidden) status code.

      3. The interceptor component picks up on this 403 status and redirects the user to a "forbidden" page.


      This all works fine, however



      Even though the interceptor is picking up on the 403 and doing a redirect, the reuse strategy component still caches the /blogs page into it's array of cached pages. So, when the user clicks the link to go to the /blogs route again, the cache kicks in and provides the page to the user and as no http request is made this time due to it being pulled from the reuse cache, the 403 forbidden is not picked up in the interceptor so the user is shown a half rendered /blogs page (with no data as the webapi didn't return any).



      Is there a way for me to prevent that /blogs page being placed into the reuse cache when it is on a 403 forbidden status?



      I have tried to look inside the reuse cache just before I redirect to the forbidden page in the interceptor but at that point the cache does not have the /blogs item. It must be being added after the interceptor has completed it's work.



      I understand the link can be hidden if the user does not have the role but for arguments sake, let's say the link is visible even without the correct role.



      So, can I prevent it going in the cache or can I remove it from the cache somehow based on the interceptor.



      Hope someone can advise.



      Thanks.



      custom-reuse-strategy.ts




      import { RouteReuseStrategy, DetachedRouteHandle, ActivatedRouteSnapshot } from "@angular/router";
      import { SignInComponent } from "./user/sign-in/sign-in.component";


      export class CustomReuseStrategy implements RouteReuseStrategy {

      private handlers: {[key: string]: DetachedRouteHandle} = {};

      private cachedUrls = [
      /home/
      ]

      constructor() {}

      shouldDetach(route: ActivatedRouteSnapshot): boolean {
      return true;
      }

      store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
      let url = route.url.join("/") || route.parent.url.join("/");
      //Don't cache the following urls...
      if(url.startsWith('member/view/') || url.startsWith('post/') || url === "home"){
      return;
      }
      this.handlers[url] = handle;
      }

      shouldAttach(route: ActivatedRouteSnapshot): boolean {
      let url = route.url.join("/") || route.parent.url.join("/");
      //Logout - remove all cached routes
      if (route.component == SignInComponent) {
      this.handlers = {};
      return false;
      }

      //If this route is cached - load up the cached information
      for (let preservedUrl of this.cachedUrls) {
      if (preservedUrl.test(url)) {
      return false;
      }
      }
      return !!this.handlers[url];
      }

      retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
      return this.handlers[route.url.join("/") || route.parent.url.join("/")];
      }

      shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
      return future.routeConfig === curr.routeConfig;
      }


      }


      auth.interceptor.ts





      import { HttpInterceptor, HttpRequest, HttpHandler, HttpUserEvent, HttpEvent } from "@angular/common/http";
      import { Observable } from "rxjs";
      import { tap } from 'rxjs/operators';
      import { Injectable } from "@angular/core";
      import { Router } from "@angular/router";


      @Injectable()
      export class AuthInterceptor implements HttpInterceptor {

      constructor(private router: Router) { }

      intercept(req: HttpRequest, next: HttpHandler): Observable> {
      if (req.headers.get('No-Auth') == "True")
      {
      return next.handle(req.clone());
      }

      if (localStorage.getItem('userToken') != null) {
      const clonedreq = req.clone({
      headers: req.headers.set("Authorization", "Bearer " + localStorage.getItem('userToken'))
      });

      return next.handle(clonedreq).pipe
      (
      tap(
      succ => { },
      err => {
      if (err.status === 401){
      localStorage.removeItem('userToken');
      this.router.navigateByUrl('/account/login');
      }
      else if (err.status === 403){
      this.router.navigateByUrl('/forbidden');
      }
      }
      )
      );
      }
      else {
      this.router.navigateByUrl('/account/login');
      }
      }
      }










      share|improve this question
















      Hope someone can guide me on this issue.



      Coding an Angular 6 application, I am using the Custom-Reuse-Strategy to cache pages the user has been to and also a HttpInterceptor to handle 401/403 type
      requests.



      My issue is when this set of conditions apply:




      1. The user clicks on say a link that goes to /blogs

      2. The http request is made to my dotnet webapi controller which checks the users roles e.g. "Author". The controller identifies this user as not having the "Author" role so it returns back a 403 (forbidden) status code.

      3. The interceptor component picks up on this 403 status and redirects the user to a "forbidden" page.


      This all works fine, however



      Even though the interceptor is picking up on the 403 and doing a redirect, the reuse strategy component still caches the /blogs page into it's array of cached pages. So, when the user clicks the link to go to the /blogs route again, the cache kicks in and provides the page to the user and as no http request is made this time due to it being pulled from the reuse cache, the 403 forbidden is not picked up in the interceptor so the user is shown a half rendered /blogs page (with no data as the webapi didn't return any).



      Is there a way for me to prevent that /blogs page being placed into the reuse cache when it is on a 403 forbidden status?



      I have tried to look inside the reuse cache just before I redirect to the forbidden page in the interceptor but at that point the cache does not have the /blogs item. It must be being added after the interceptor has completed it's work.



      I understand the link can be hidden if the user does not have the role but for arguments sake, let's say the link is visible even without the correct role.



      So, can I prevent it going in the cache or can I remove it from the cache somehow based on the interceptor.



      Hope someone can advise.



      Thanks.



      custom-reuse-strategy.ts




      import { RouteReuseStrategy, DetachedRouteHandle, ActivatedRouteSnapshot } from "@angular/router";
      import { SignInComponent } from "./user/sign-in/sign-in.component";


      export class CustomReuseStrategy implements RouteReuseStrategy {

      private handlers: {[key: string]: DetachedRouteHandle} = {};

      private cachedUrls = [
      /home/
      ]

      constructor() {}

      shouldDetach(route: ActivatedRouteSnapshot): boolean {
      return true;
      }

      store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
      let url = route.url.join("/") || route.parent.url.join("/");
      //Don't cache the following urls...
      if(url.startsWith('member/view/') || url.startsWith('post/') || url === "home"){
      return;
      }
      this.handlers[url] = handle;
      }

      shouldAttach(route: ActivatedRouteSnapshot): boolean {
      let url = route.url.join("/") || route.parent.url.join("/");
      //Logout - remove all cached routes
      if (route.component == SignInComponent) {
      this.handlers = {};
      return false;
      }

      //If this route is cached - load up the cached information
      for (let preservedUrl of this.cachedUrls) {
      if (preservedUrl.test(url)) {
      return false;
      }
      }
      return !!this.handlers[url];
      }

      retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
      return this.handlers[route.url.join("/") || route.parent.url.join("/")];
      }

      shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
      return future.routeConfig === curr.routeConfig;
      }


      }


      auth.interceptor.ts





      import { HttpInterceptor, HttpRequest, HttpHandler, HttpUserEvent, HttpEvent } from "@angular/common/http";
      import { Observable } from "rxjs";
      import { tap } from 'rxjs/operators';
      import { Injectable } from "@angular/core";
      import { Router } from "@angular/router";


      @Injectable()
      export class AuthInterceptor implements HttpInterceptor {

      constructor(private router: Router) { }

      intercept(req: HttpRequest, next: HttpHandler): Observable> {
      if (req.headers.get('No-Auth') == "True")
      {
      return next.handle(req.clone());
      }

      if (localStorage.getItem('userToken') != null) {
      const clonedreq = req.clone({
      headers: req.headers.set("Authorization", "Bearer " + localStorage.getItem('userToken'))
      });

      return next.handle(clonedreq).pipe
      (
      tap(
      succ => { },
      err => {
      if (err.status === 401){
      localStorage.removeItem('userToken');
      this.router.navigateByUrl('/account/login');
      }
      else if (err.status === 403){
      this.router.navigateByUrl('/forbidden');
      }
      }
      )
      );
      }
      else {
      this.router.navigateByUrl('/account/login');
      }
      }
      }







      angular caching angular6 angular-http-interceptors






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 21 '18 at 9:35







      Rowie

















      asked Nov 20 '18 at 18:17









      RowieRowie

      205




      205
























          0






          active

          oldest

          votes











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53399145%2fhow-can-i-prevent-the-angular-6-custom-reuse-strategy-from-caching-a-403-forbidd%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          0






          active

          oldest

          votes








          0






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53399145%2fhow-can-i-prevent-the-angular-6-custom-reuse-strategy-from-caching-a-403-forbidd%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          這個網誌中的熱門文章

          Xamarin.form Move up view when keyboard appear

          Post-Redirect-Get with Spring WebFlux and Thymeleaf

          Anylogic : not able to use stopDelay()