How can I prevent the Angular 6 Custom-Reuse-Strategy from caching a 403 forbidden page?
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:
- The user clicks on say a link that goes to /blogs
- 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.
- 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
add a comment |
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:
- The user clicks on say a link that goes to /blogs
- 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.
- 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
add a comment |
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:
- The user clicks on say a link that goes to /blogs
- 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.
- 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
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:
- The user clicks on say a link that goes to /blogs
- 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.
- 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
angular caching angular6 angular-http-interceptors
edited Nov 21 '18 at 9:35
Rowie
asked Nov 20 '18 at 18:17
RowieRowie
205
205
add a comment |
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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