Security for an AngularJs + ServiceStack App
Asked Answered
S

3

3

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

Shinberg answered 31/7, 2013 at 17:42 Comment(5)
Are both the site and the service being hosted on the same domain?Artima
@Artima yes they are going to be in the same domain and they will be under the same context/ app pool in a IIS 7Shinberg
By secure, do you mean you want to restrict access by some kind of authentication method?Alfaro
@JohnTseng yes that's what I meant! thanks!Shinberg
You'll need to have some kind of authentication for those files/directories. Maybe http authentication. Not sure how you do it in servicestack. We do it with http modules based on cookies.Alfaro
S
5

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="#/">header menu</a>
      <ul class="nav">
         <li ng-class="{active: routeIs('/Dashboard')}"><a href="#/Dashboard">Dashboard</a></li>
         <li ng-class="{active: routeIs('/Login')}"><a href="#/Login">Login</a></li>
         <li ng-class="{active: routeIs('/Payments')}"><a href="#/Payments">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

Shinberg answered 5/8, 2013 at 18:44 Comment(3)
@Pendro this is correct way of doing things. When you are working with REST based API either yours or someone else you security is based on cookie provided by API. Same is done by servicestack also. So, that much part you need to do. And same you are doing here. More over you can move to https if you like or block request headers too. If you want more details then let me know. Will try to provide links and examples.Faucher
if you got the answer then it is better to select as answer and close it. :)Faucher
@Faucher thanks for such a great help, I'm still working on the security part, step by step I still need to implement ng-sanitize - Laravel CSRF support, route filters, etc, but for the time being the basic authentication is working so far that's what I was trying to resolve with this question.Shinberg
R
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;
}); 
Reinaldo answered 1/8, 2013 at 16:24 Comment(4)
thanks! @marfarma what's the case if the files are static htmls? or if I'm sending ajax requests?Shinberg
As long as ServiceStack is serving the file, rather than an httpd server (IIS, Apache, Ngnix, etc.) this catchall handler will work. You just have to adjust the conditional expression to your requirements. See the RockStars code for configuration examples. If ServiceStack is serving your protected static assets then it's easy to integrate auth checks & it won't matter how your client requests them (ajax or not) - if the requester isn't authenticated, the asset won't be served.Reinaldo
In case you haven't seen it, here's a tutorial that covers adding custom authentication to a ServiceStack project: docs.auth0.com/servicestack-tutorialReinaldo
thanks for the links those was pretty useful, the difficult part was to put everything together but I've done some work and I've updated the post with an approach.Shinberg
J
0

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.

Jackofalltrades answered 5/8, 2013 at 7:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.