{"id":71804,"date":"2020-01-10T16:54:20","date_gmt":"2020-01-10T11:24:20","guid":{"rendered":"https:\/\/www.vskills.in\/certification\/tutorial\/?p=71804"},"modified":"2024-04-12T14:22:43","modified_gmt":"2024-04-12T08:52:43","slug":"route-protection","status":"publish","type":"page","link":"https:\/\/www.vskills.in\/certification\/tutorial\/route-protection\/","title":{"rendered":"Route Protection"},"content":{"rendered":"\n<p><a href=\"https:\/\/www.vskills.in\/certification\/tutorial\/angular-7-developer-tutorials\/\" target=\"_blank\" rel=\"noreferrer noopener\">Go back to Tutorial<\/a><\/p>\n\n\n<p>Securing routes with the new component router is one of these and it can be difficult to figure out. Here\u2019s the approach I\u2019m using which seems to be working well for me and has been reusable across multiple projects.<\/p>\n<p>First of all, this is for declarative security only. That is, where the rules can be statically defined on the route. It should be adaptable to work with whatever authentication system your app uses but is particularly suited to using JSON Web Tokens which can contain the roles that your user has been granted.<\/p>\n<p>If you need per-object permission checks, doing these within the component and \/ or service that is responsible for accessing and handling them.<\/p>\n<p>The natural place to declare the permissions for a route is on the route config which provides a data property. While we could add a flag to indicate if a route should be public or not, it seems a little superfluous as routes are public by default and so the flag would only ever add new information if set to false. As we\u2019re also going to define roles that the user requires we can make that do double-duty and use it\u2019s presence to indicate that we need authentication but it can be empty if we don\u2019t care about any specific roles which is the same as saying we only care that the user is authenticated.<\/p>\n<p>Here\u2019s an example of three routes, the first one is open to all, the second one only available to authenticated users (but no roles specified) and the last one requiring the user has the role \u2018admin\u2019.<\/p>\n<p>@RouteConfig([<\/p>\n<p>{ path:&#8217;\/open2all&#8217;, component:OpenComponent, name:&#8217;Open&#8217; }<\/p>\n<p>{ path:&#8217;\/needauth&#8217;, component:AuthComponent, name:&#8217;Auth&#8217;, data:{ roles:[] }}<\/p>\n<p>{ path:&#8217;\/needrole&#8217;, component:RoleComponent, name:&#8217;Role&#8217;, data:{ roles:[&#8216;admin&#8217;] }}<\/p>\n<p>])<\/p>\n<p>So that\u2019s the permissions for our routes defined &#8211; the easy part! We want to be able to check these permissions as part of the routing process and the natural place to do this is the &lt;router-outlet&gt; so we are going to create our own &lt;secure-outlet&gt; version that will override the activate method to do the permission checks. But what if permission fails? What do we want to happen? There are two scenarios:<\/p>\n<ul>\n<li>A route that requires authentication when the user has not been authenticated. The natural thing to do is to redirect to the sign-in route to allow the user to sign-in and then return back to our protected route.<\/li>\n<li>A route that requires certain roles than an authenticated user does not have. The user doesn\u2019t have access and should be redirected to a permission denied route.<\/li>\n<\/ul>\n<p>So we need our secure router to be configureable with two routes &#8211; one for sign-in and one for unauthorized access. We can pass these as properties in the view of our routing component which will look like this:<\/p>\n<p>&lt;secure-outlet signin=&#8221;\/Signin&#8221; unauthorized=&#8221;\/Denied&#8221;&gt;&lt;\/secure-outlet&gt;<\/p>\n<p>All the magic will happen in the &lt;secure-outlet&gt; component but we don\u2019t want to couple it directly to our app-specific authentication service as this can make it harder to re-use. Instead we\u2019ll define an interface that our auth service needs to supply to allow it to be used by this component.<\/p>\n<p>export abstract class IAuthService {<\/p>\n<p>\/\/ is the current user authenticated?<\/p>\n<p>abstract isAuthenticated():boolean;<\/p>\n<p>\/\/ does the current user have one of these roles?<\/p>\n<p>abstract hasRole(roles: string[]):boolean;<\/p>\n<p>}<\/p>\n<p>This should be straightforward to implement into any AuthService our app uses but one subtle thing to ensure is that when we ask for an instance of the IAuthService we\u2019re actually give the instance of the AuthService used by the app (whatever it is called). We do this by setting the provider to use in our app bootstrap using the useExisting option which prevents us getting a separate instance when the AuthService itself will also likely be configured:<\/p>\n<p>bootstrap(App, [<\/p>\n<p>AUTH_HTTP_PROVIDERS,<\/p>\n<p>\/\/ more providers &#8230;<\/p>\n<p>provide(IAuthService, { useExisting: AuthService }),<\/p>\n<p>AuthService,<\/p>\n<p>]);<\/p>\n<p>Finally, we\u2019re ready to create our &lt;secure-outlet&gt; component which will provide the permissions checks and handle the route redirects if they fail:<\/p>\n<p>import {Directive, Attribute, ElementRef, DynamicComponentLoader} from &#8216;angular2\/core&#8217;;<\/p>\n<p>import {Router, RouteData, RouterOutlet, ComponentInstruction} from &#8216;angular2\/router&#8217;;<\/p>\n<p>@Directive({selector: &#8216;secure-outlet&#8217;})<\/p>\n<p>export class SecureRouterOutlet extends RouterOutlet {<\/p>\n<p>signin:string;<\/p>\n<p>unauthorized:string;<\/p>\n<p>private parentRouter: Router;<\/p>\n<p>private authService: IAuthService;<\/p>\n<p>constructor(_elementRef: ElementRef, _loader: DynamicComponentLoader,<\/p>\n<p>_parentRouter: Router, @Attribute(&#8216;name&#8217;) nameAttr: string,<\/p>\n<p>authService:IAuthService,<\/p>\n<p>@Attribute(&#8216;signin&#8217;) signinAttr: string,<\/p>\n<p>@Attribute(&#8216;unauthorized&#8217;) unauthorizedAttr: string) {<\/p>\n<p>super(_elementRef, _loader, _parentRouter, nameAttr);<\/p>\n<p>this.parentRouter = _parentRouter;<\/p>\n<p>this.authService = authService;<\/p>\n<p>this.signin = signinAttr;<\/p>\n<p>this.unauthorized = unauthorizedAttr;<\/p>\n<p>}<\/p>\n<p>activate(nextInstruction: ComponentInstruction): Promise&lt;any&gt; {<\/p>\n<p>var roles = &lt;string[]&gt;nextInstruction.routeData.data[&#8216;roles&#8217;];<\/p>\n<p>\/\/ no roles defined means route has no restrictions so activate<\/p>\n<p>if (roles == null) {<\/p>\n<p>return super.activate(nextInstruction);<\/p>\n<p>}<\/p>\n<p>\/\/ if user isn&#8217;t authenticated then redirect to sign-in route<\/p>\n<p>\/\/ pass the URL to this route for redirecting back after auth<\/p>\n<p>\/\/ TODO: include querystring parameters too?<\/p>\n<p>if (!this.authService.isAuthenticated()) {<\/p>\n<p>var ins = this.parentRouter.generate([this.signin,{url:location.pathname}]);<\/p>\n<p>return super.activate(ins.component);<\/p>\n<p>}<\/p>\n<p>\/\/ if no specific roles are required *or* the user has one of the<\/p>\n<p>\/\/ roles required then the route can be activated<\/p>\n<p>if (roles.length == 0 || this.authService.hasRole(roles)) {<\/p>\n<p>return super.activate(nextInstruction);<\/p>\n<p>}<\/p>\n<p>\/\/ user has insufficient role permissions so redirect to denied<\/p>\n<p>var ins = this.parentRouter.generate([this.unauthorized]);<\/p>\n<p>return super.activate(ins.component);<\/p>\n<p>}<\/p>\n<p>reuse(nextInstruction: ComponentInstruction): Promise&lt;any&gt; {<\/p>\n<p>return super.reuse(nextInstruction);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>Now we just need to make sure our applications AuthService (whatever it is called) provides the necessary pieces:<\/p>\n<p>import { IAuthService } from &#8216;..\/components\/secure-outlet\/secure-outlet&#8217;;<\/p>\n<p>@Injectable()<\/p>\n<p>export class AuthService extends IAuthService {<\/p>\n<p>user:User;<\/p>\n<p>isAuthenticated():boolean {<\/p>\n<p>return this.user !== null;<\/p>\n<p>}<\/p>\n<p>hasRole(string[] roles):boolean {<\/p>\n<p>return this.isAuthenticate() &amp;&amp; [check intersection of user roles]\n<p>}&nbsp;&nbsp; \/\/ other auth functionality, sign-in, token handling etc<\/p>\n<p>}<\/p>\n<p>And there we have it. Permissions declared on our routes and handled for us.<\/p>\n<p>Just be sure to have the sign-in route check for the url parameter it is sent and redirect back to it after authentication has been completed.<\/p>\n\n\n<p><a href=\"https:\/\/www.vskills.in\/certification\/tutorial\/angular-7-developer-tutorials\/\" target=\"_blank\" rel=\"noreferrer noopener\">Go back to Tutorial<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Go back to Tutorial Securing routes with the new component router is one of these and it can be difficult to figure out. Here\u2019s the approach I\u2019m using which seems to be working well for me and has been reusable across multiple projects. First of all, this is for declarative security only. That is, where&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"categories":[8294],"tags":[8367],"class_list":["post-71804","page","type-page","status-publish","hentry","category-angular-7","tag-route-protection"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Route Protection - Tutorial<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.vskills.in\/certification\/tutorial\/route-protection\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Route Protection - Tutorial\" \/>\n<meta property=\"og:description\" content=\"Go back to Tutorial Securing routes with the new component router is one of these and it can be difficult to figure out. Here\u2019s the approach I\u2019m using which seems to be working well for me and has been reusable across multiple projects. First of all, this is for declarative security only. That is, where...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.vskills.in\/certification\/tutorial\/route-protection\/\" \/>\n<meta property=\"og:site_name\" content=\"Tutorial\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/vskills.in\/\" \/>\n<meta property=\"article:modified_time\" content=\"2024-04-12T08:52:43+00:00\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.vskills.in\/certification\/tutorial\/route-protection\/\",\"url\":\"https:\/\/www.vskills.in\/certification\/tutorial\/route-protection\/\",\"name\":\"Route Protection - Tutorial\",\"isPartOf\":{\"@id\":\"https:\/\/www.vskills.in\/certification\/tutorial\/#website\"},\"datePublished\":\"2020-01-10T11:24:20+00:00\",\"dateModified\":\"2024-04-12T08:52:43+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.vskills.in\/certification\/tutorial\/route-protection\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.vskills.in\/certification\/tutorial\/route-protection\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.vskills.in\/certification\/tutorial\/route-protection\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.vskills.in\/certification\/tutorial\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Route Protection\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.vskills.in\/certification\/tutorial\/#website\",\"url\":\"https:\/\/www.vskills.in\/certification\/tutorial\/\",\"name\":\"Tutorial\",\"description\":\"Vskills - A initiative in elearning and certification\",\"publisher\":{\"@id\":\"https:\/\/www.vskills.in\/certification\/tutorial\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.vskills.in\/certification\/tutorial\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.vskills.in\/certification\/tutorial\/#organization\",\"name\":\"Vskills\",\"url\":\"https:\/\/www.vskills.in\/certification\/tutorial\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.vskills.in\/certification\/tutorial\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.vskills.in\/certification\/tutorial\/wp-content\/uploads\/2017\/07\/vskills-min-logo.jpg\",\"contentUrl\":\"https:\/\/www.vskills.in\/certification\/tutorial\/wp-content\/uploads\/2017\/07\/vskills-min-logo.jpg\",\"width\":73,\"height\":55,\"caption\":\"Vskills\"},\"image\":{\"@id\":\"https:\/\/www.vskills.in\/certification\/tutorial\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/vskills.in\/\",\"https:\/\/x.com\/vskills_in\",\"https:\/\/www.linkedin.com\/company-beta\/1371554\/\",\"https:\/\/www.youtube.com\/channel\/UCMWnscxPwRF_PqXo9B7q_Tw\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Route Protection - Tutorial","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.vskills.in\/certification\/tutorial\/route-protection\/","og_locale":"en_US","og_type":"article","og_title":"Route Protection - Tutorial","og_description":"Go back to Tutorial Securing routes with the new component router is one of these and it can be difficult to figure out. Here\u2019s the approach I\u2019m using which seems to be working well for me and has been reusable across multiple projects. First of all, this is for declarative security only. That is, where...","og_url":"https:\/\/www.vskills.in\/certification\/tutorial\/route-protection\/","og_site_name":"Tutorial","article_publisher":"https:\/\/www.facebook.com\/vskills.in\/","article_modified_time":"2024-04-12T08:52:43+00:00","twitter_misc":{"Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.vskills.in\/certification\/tutorial\/route-protection\/","url":"https:\/\/www.vskills.in\/certification\/tutorial\/route-protection\/","name":"Route Protection - Tutorial","isPartOf":{"@id":"https:\/\/www.vskills.in\/certification\/tutorial\/#website"},"datePublished":"2020-01-10T11:24:20+00:00","dateModified":"2024-04-12T08:52:43+00:00","breadcrumb":{"@id":"https:\/\/www.vskills.in\/certification\/tutorial\/route-protection\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.vskills.in\/certification\/tutorial\/route-protection\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.vskills.in\/certification\/tutorial\/route-protection\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.vskills.in\/certification\/tutorial\/"},{"@type":"ListItem","position":2,"name":"Route Protection"}]},{"@type":"WebSite","@id":"https:\/\/www.vskills.in\/certification\/tutorial\/#website","url":"https:\/\/www.vskills.in\/certification\/tutorial\/","name":"Tutorial","description":"Vskills - A initiative in elearning and certification","publisher":{"@id":"https:\/\/www.vskills.in\/certification\/tutorial\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.vskills.in\/certification\/tutorial\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.vskills.in\/certification\/tutorial\/#organization","name":"Vskills","url":"https:\/\/www.vskills.in\/certification\/tutorial\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.vskills.in\/certification\/tutorial\/#\/schema\/logo\/image\/","url":"https:\/\/www.vskills.in\/certification\/tutorial\/wp-content\/uploads\/2017\/07\/vskills-min-logo.jpg","contentUrl":"https:\/\/www.vskills.in\/certification\/tutorial\/wp-content\/uploads\/2017\/07\/vskills-min-logo.jpg","width":73,"height":55,"caption":"Vskills"},"image":{"@id":"https:\/\/www.vskills.in\/certification\/tutorial\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/vskills.in\/","https:\/\/x.com\/vskills_in","https:\/\/www.linkedin.com\/company-beta\/1371554\/","https:\/\/www.youtube.com\/channel\/UCMWnscxPwRF_PqXo9B7q_Tw"]}]}},"_links":{"self":[{"href":"https:\/\/www.vskills.in\/certification\/tutorial\/wp-json\/wp\/v2\/pages\/71804","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.vskills.in\/certification\/tutorial\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.vskills.in\/certification\/tutorial\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.vskills.in\/certification\/tutorial\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.vskills.in\/certification\/tutorial\/wp-json\/wp\/v2\/comments?post=71804"}],"version-history":[{"count":4,"href":"https:\/\/www.vskills.in\/certification\/tutorial\/wp-json\/wp\/v2\/pages\/71804\/revisions"}],"predecessor-version":[{"id":87903,"href":"https:\/\/www.vskills.in\/certification\/tutorial\/wp-json\/wp\/v2\/pages\/71804\/revisions\/87903"}],"wp:attachment":[{"href":"https:\/\/www.vskills.in\/certification\/tutorial\/wp-json\/wp\/v2\/media?parent=71804"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.vskills.in\/certification\/tutorial\/wp-json\/wp\/v2\/categories?post=71804"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.vskills.in\/certification\/tutorial\/wp-json\/wp\/v2\/tags?post=71804"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}