Security for an AngularJs + ServiceStack App

All we need is an easy explanation of the problem, so here it is.

I have an application that have four modules in the front end, I’m trying to use as much as possible AngularJs in the front end I’m using an empty website asp.net project to host all the files and the REST serviceStack, my project have kind of the following structure:

~/ (web.config, global.asax and all the out of the box structure for an asp.net website)
- App <-  AngularJs 
    - Users  <-  js controllers and views (static html files)
    - Companies
    - BackEnd
    - Public
    Index.html
    IndexCtrl.js
    App.js
- Content
- Js

I use angularjs service calls and the backend I’m using REST with servicestack.

the question is how can I restrict the access only to authenticated users to those static html files? let’s say the ones that are inside inside Companies, Backend and users for example

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

Hi After doing some research this is the solution that worked for me:

  1. Install razor markdown from nuget
  2. Change the file structure to match the default behavior RM [Razor Markdown] to /views
  3. Modify the web config following the approach described in this service stack example
  4. Change all the static htmls files to .cshtml files, this by default creates the same route without the extension like /views/{Pagename} without the extension, I’m just using this approach to get the authorization logic simpler to implement (at least for me)
  5. Update the service method with an authorize attribute you can find out more in this page

to illustrate a lit of bit more this is my route definition in so far:

'use strict';
angular.module('myApp', ['myApp.directives', 'myApp.services']).config(
    ['$routeProvider', function($routeProvider) {
        $routeProvider.when('/Dashboard', {
            controller: 'dashboardCtrl',
            templateUrl: 'Views/dashboard'
            }).when('/Payments', {
            controller: 'paymentsCtrl',
            templateUrl: 'Views/payments'
        }).
            when('/Login', {
                controller: 'loginCtrl',
                templateUrl: 'Views/login'
            });
    }]

);

Notice that the references are pointed now to the razor paths.

this is a small menu I’ve done in angular

<div class="container">

  <div class="navbar" ng-controller="indexCtrl">
    <div class="navbar-inner">
      <a class="brand" href="#/" rel="nofollow noreferrer noopener">header menu</a>
      <ul class="nav">
         <li ng-class="{active: routeIs('/Dashboard')}"><a href="#/Dashboard" rel="nofollow noreferrer noopener">Dashboard</a></li>
         <li ng-class="{active: routeIs('/Login')}"><a href="#/Login" rel="nofollow noreferrer noopener">Login</a></li>
         <li ng-class="{active: routeIs('/Payments')}"><a href="#/Payments" rel="nofollow noreferrer noopener">payments</a></li>
      </ul>
    </div>
  </div>


  <ng-view></ng-view>

</div>

let’s say that the payments page is restricted, so every time I click on a the page I get a 401 unauthorized message.

Service host:

 public override void Configure(Container container)
        { 

            Plugins.Add(new AuthFeature(() => new AuthUserSession(), new IAuthProvider[] {
                new FacebookAuthProvider(appSettings), 
                new TwitterAuthProvider(appSettings), 
                new BasicAuthProvider(appSettings), 
                new GoogleOpenIdOAuthProvider(appSettings),
                new CredentialsAuthProvider()
            })); //I'm going to support social auth as well.

            Plugins.Add(new RegistrationFeature());

            Routes.Add<UserRequest>("/Api/User/{Id}");
            Routes.Add<LoginRequest>("/Api/User/login","POST");
            Routes.Add<PaymentRequest>("/views/Payments");


        }

I hope that helps

Method 2

Create a CatchAllHander method to check for restricted routes and, for those static files that require authentication, return the ForbiddenFileHander if not authenticated, otherwise return null. Given an isAuthenticated method and restrictedDirs is defined somewhere – maybe your app or web config file, it can be as simple as:

appHost.CatchAllHandlers.Add((httpMethod, pathInfo, filePath) => {
   if ( restrictedDirs.ContainsKey(pathInfo) && !isAuthenticated())
      return new ForbiddenHttpHandler();
   return null;
}); 

Method 3

Why not use Forms Authentication? Simply add a few < location > tags to your web.config to allow/disallow different sections, you can even do it based on roles.

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply