Security for an AngularJs + ServiceStack App - asp.net

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

Hi After doing some research this is the solution that worked for me:
Install razor markdown from nuget
Change the file structure to match the default behavior RM [Razor Markdown] to /views
Modify the web config following the approach described in this service stack example
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)
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')}">Dashboard</li>
<li ng-class="{active: routeIs('/Login')}">Login</li>
<li ng-class="{active: routeIs('/Payments')}">payments</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

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;
});

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.

Related

Why won't CSS won't work on specific situation

So I'm working a project of a Website. In it, there's an admin page where I can add or remove images that will be shown on the website. I created a Controller for the Main Admin page alone, and then I created a controller for every type of information that can be changed through that page (Porfolio, banner, etc). All the pages are styled by CSS. So when my AdmController returns the view with the main Admin page, everything works fine
The adress for the main Admin Page results in localhost:8000/adm
But once I try to open a view where I would add an image to be shown on the Main page, CSS simply won't work. To acess, say, the add banner page, I have a BannerController that will return a "form-banner" view, resulting in the adress localhost:8000/adm/banner. In this page CSS does not work.
I wanted to test further so I created a new Route that would take me directly to the create banner page without going through the admin page, and also not using any Controllers at all. I got the adress localhost:8000/banner. Now CSS works.
Any ideas why?
These are the routes including the one I created just to test the view:
Route::resource('adm', 'AdmController');
Route::resource('adm/banner', 'BannerController');
Route::get('banner', function () {
return view('admin/form-banner');
});
This is the AdmController:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class AdmController extends Controller
{
public function index()
{
return view('admin/index');
}
}
This is how the BannerController is returning the mal-functioning View:
public function create()
{
return view('admin/form-banner')
And this is the point in the Main Adm View (the one that works) where It calls the BannerController:
<ul class="nav-second-level" aria-expanded="false">
<li>Create new banner</li>
Add your CSS like below
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
the absolute path after your public folder

How to render Svelte Server-side?

Can I somehow produce "initial" HTML files using Svelte?
I am using Django, Webpack and Tailwindcss. I want to use Svelte with my frontend, but I don't want to give up the speed that comes with simply using server-side rendering (Django templates). If what I present initially is a bootstrap HTML page that pulls in the bundle.js and Svelte builds the DOM on the client side, then the browsers only starts downloading images only after the JS file is loaded.
Compare this to having the initially rendered HTML that already contains links to images, the browser starts downloading them alongside the JS making for faster perceived page loading.
I do not want to use Sapper as my application server, I want to continue using Django.
The challenge is sharing state (props) between your Django app and the Svelte components.
To get the HTML code from a component:
require('svelte/register')
const MyComponent = require('./MyComponent.svelte').default
const { html } = MyComponent.render({ ...props... })
If the components has no props, you can compile and cache the HTML templates (maybe even before runtime).
If you want to send props dynamically, for example based on data in your database, then you need to do so at runtime. That means executing JS server-side. Performance won't be bad if you cache the result.
If you can't cache, then using Django for performance would be negated, because you'd be executing Svelte anyways, so might as well use Svelte to do the whole server-side job, and then use Django as a backend server.
According to this blog post you do the following instructions:
In the following post I will show how to make use of server-side
rendering in Svelte.
Most of the time you will probably run your Svelte code client-side,
but there are scenarios where you can benefit from server-side Svelte
rendering.
SEO In my opinion the primary use case for server-side rendering is
SEO. Doing an initial rendering on the server will make your website
much more crawler accessible. Crawlers typically support some
JavaScript execution, but a complex JavaScript application is unlikely
to be indexed correctly.
My experience is that applications that make ajax calls to fetch data
are particularly challenging to index. The crawler might successfully
render the initial static part of the application, but the data will
be missing since the crawler won't make the necessary ajax calls.
Doing the initial rendering on the server allows crawlers to download
the application as fully constructed html. There is no need to execute
JavaScript on the client to compose the initial view since the view
was already built on the server.
Server-side vs Client-side Technically you could build a Svelte
application without any client side components, but it would be
completely static. Basically the application would behave much like an
old server-side PHP application. Great for crawlers, but real users
typically expect a richer user experience.
This is where server-side meets client-side.
Once the server generated html is fully rendered in the browser, we
can start a client-side counterpart of the application. The
client-side version picks up where the server side application left
off.
Both versions of the application may use the same Svelte components,
but it's important to understand that they execute independently of
each other. The server-side version does not know about the
client-side version and vice versa.
It's also important to understand that there is no default state
sharing between client and server (e.g. data property).
Article Carousel I decided to use server side Svelte to build an
article carousel for the landing page of my blog. The idea is to use a
Svelte component to cycle through articles in four of my article
categories.
The carousel should load instantly on page load, so I decided to
render the initial view on the server. Once the page has loaded I
start the client-side counterpart of the Svelte component to
dynamically cycle through the articles.
I am not known for css or design skills, so don't expect a pretty UI,
but here's how I wired everything up.
I start by creating an Article component that will be used to render
the articles in the carousel. The component should probably be split
into two components, but keeping it as one for the purposes of this
blog post.
<div class="row">
<span class="slide-show-card col-sm-3">
<h4>Angular</h4>
<h5><a class="slide-show-link" href="{{angularUrl}}">{{angularTitle}}</a></h5>
<div class="label label-success slide-show-count">Viewed {{angular.viewCount}} times</div>
<div>{{angularIntro}}</div>
</span>
<span class="slide-show-card col-sm-3">
<h4>JavaScript</h4>
<h5><a class="slide-show-link" href="{{javascriptUrl}}">{{javascriptTitle}}</a></h5>
<div class="label label-success slide-show-count">Viewed {{javascript.viewCount}} times</div>
<div>{{javascriptIntro}}</div>
</span>
<span class="slide-show-card col-sm-3">
<h4>Svelte</h4>
<h5><a class="slide-show-link" href="{{svelteUrl}}">{{svelteTitle}}</a></h5>
<div class="label label-success slide-show-count">Viewed {{svelte.viewCount}} times</div>
<div>{{svelteIntro}}</div>
</span>
<span class="slide-show-card col-sm-3">
<h4>React</h4>
<h5><a class="slide-show-link" href="{{reactUrl}}">{{reactTitle}}</a></h5>
<div class="label label-success slide-show-count">Viewed {{react.viewCount}} times</div>
<div>{{reactIntro}}</div>
</span>
</div>
<script>
class ArticleService {
constructor() {
this.articles = [];
this.index = {
'angular': -1,
'javascript': -1,
'svelte': -1,
'react': -1
};
}
getArticles() {
return fetch('/full-article-list-json')
.then((data) => {
return data.json();
})
.then((articles) => {
this.articles = articles;
return articles;
});
}
getNextArticle(key) {
this.index[key] = (this.index[key] + 1) % this.articles[key].length;
let a = this.articles[key][this.index[key]];
return a;
}
}
let articleService = new ArticleService();
export default {
onrender() {
let update = () => {
this.set({angular: articleService.getNextArticle('angular')});
this.set({javascript: articleService.getNextArticle('javascript')});
this.set({svelte: articleService.getNextArticle('svelte')});
this.set({react: articleService.getNextArticle('react')});
};
articleService.getArticles()
.then((articles) => {
update();
if(typeof global === 'undefined') {
document.querySelector('#articles').innerHTML = '';
document.querySelector('#articles-client-side').style.display =
"block";
}
})
.then(() => {
setInterval(() => {
articleService.getArticles()
.then((articles) => {
update();
});
}, 5000);
});
},
data () {
return {}
},
computed: {
angularTitle: angular => angular.title || '',
angularIntro: angular => angular.intro || '',
angularUrl: angular => `viewarticle/${angular.friendlyUrl}`,
javascriptTitle: javascript => javascript.title || '',
javascriptIntro: javascript => javascript.intro || '',
javascriptUrl: javascript => `viewarticle/${javascript.friendlyUrl}`,
svelteTitle: svelte => svelte.title || '',
svelteIntro: svelte => svelte.intro || '',
svelteUrl: svelte => `viewarticle/${svelte.friendlyUrl}`,
reactTitle: react => react.title || '',
reactIntro: react => react.intro || '',
reactUrl: react => `viewarticle/${react.friendlyUrl}`,
}
}
</script>
Server Let's take a look at the server code.
The first thing we have to do is activate the compiler by requiring
svelte/ssr/register
require( 'svelte/ssr/register' );
Next we have to require the component html file to get a handle to the
component.
We then call the render method and pass it an initial data object. The
data object is a standard Svelte data object.
app.get('/', function(req, res) {
var component = require('./app/article-show/Articles.html');
var articles = component.render({
angular: articles.angular,
svelte: articles.svelte,
react: articles.react,
javascript: articles.javascript
});
res.render('index.html', {articles: articles});
});
After calling render we get back a fully rendered component. We now
have to pass this to the node view engine.
In my case I am using Express with Mustache, so I can just pass the
component as an object to the render method. Then in my index.html
page I use Mustache view syntax with triple curly braces to render the
component on the page like so.
{{{articles}}} Client What we have so far is enough to render the
initial view of my component, but it won't support cycling through new
articles every few seconds.
To achieve this we have to start up a client-side version of the
Article component.
The client side version is loaded as a standard Svelte client-side
component.
import articles from './articles';
var articlesSection = new articles({
target: document.querySelector( 'main' ),
data: {angular: {}, javascript: {}, svelte: {}, react: {}}
});
Once the client-side version is activated we will have two components
in the DOM. As soon as the client-side version is ready to take over I
wipe out the server-side version.
There might be a more elegant way to do this, but I simply clear out
the server generated DOM element and flip a style on the client-side
version.
Navigation In addition to the article carousel I also built my main
navigation as a Svelte server side component. The nav is a pure server
side component with no client side counterpart.
The navigation is largely static, but it supports dynamic styling of
the active nav item. Here is the nav component code:
<div class="nav col-md-2 hidden-sm hidden-xs">
<a class="navLink" href="/"><div class="navBox {{home}}">Home</div></a>
<a class="navLink" href="/most-popular"><div class="navBox {{mostpopular}}">Most Popular</div></a>
<a class="navLink" href="/most-recent"><div class="navBox {{mostrecent}}">Most Recent</div></a>
<a class="navLink" href="/articleList/angular"><div class="navBox {{angular}}">Angular</div></a>
<a class="navLink" href="/articleList/react"><div class="navBox {{react}}">React</div></a>
<a class="navLink" href="/articleList/aurelia"><div class="navBox {{aurelia}}">Aurelia</div></a>
<a class="navLink" href="/articleList/javascript"><div class="navBox {{javascript}}">JavaScript</div></a>
<a class="navLink" href="/articleList/nodejs"><div class="navBox {{nodejs}}">NodeJS</div></a>
<a class="navLink" href="/articleList/vue"><div class="navBox {{vue}}">Vue</div></a>
<a class="navLink" href="/articleList/svelte"><div class="navBox {{svelte}}">Svelte</div></a>
<a class="navLink" href="/articleList/mongodb"><div class="navBox {{mongodb}}">MongoDB</div></a>
<a class="navLink" href="/articleList/unittesting"><div class="navBox {{unittesting}}">UnitTesting</div></a>
<a class="navLink" href="/articleList/dotnet"><div class="navBox {{dotnet}}">.Net</div></a>
<a class="navLink" href="/questions"><div class="navBox {{questions}}">Q&A</div></a>
<a class="navLink" href="/full-article-list"><div class="navBox {{all}}">All</div></a>
</div>
<script>
export default {
data () {
return {}
},
}
</script>
Because the nav is so static, there is no reason to regenerate the
server side html for every request. As an optimization I have decided
to cache the different variations of the nav. The only difference
between the different versions of the nav is that the "active" nav
items style is applied to different elements.
Here is some basic caching logic that ensures that we only generate
each nav version once.
function getNavComponent(key) {
key = key || 'home';
key = key.replace('-', '');
if(!navCache[key]) {
navCache[key] = createNavComponent(key);
}
return navCache[key];
}
function createNavComponent(key) {
var nav = require('./app/article-show/Navigation.html');
var data = {};
data[key] = 'activeNav';
return nav.render(data);
}
Demo If you want to test out my server-side vs client-side view you
can find it here.
I also loaded my site in Google web master tools to compare a
crawler's view of the component to a user's view
As you can tell from the screenshot my component looks pretty good to
crawlers after adding server side rendering.
Left side is the crawler view and the right side is the user view.

ASP.NET parameter/variable in both app Settings and app Build Events

In ASP.NET, we have Application Settings, and we have Application Pre/Post Build Events. Is it possible to access a Setting from the Pre Build Event? Or is it possible to inject the value of a Setting from the Pre Build Event?
Full context:
I have an Angular app embedded in an ASP.NET 4 Web API app. That is, my app is structured like this:
+ Solution
| - Project
| + Properties
| + AngularApp
| | + dist
| | + e2e
| | + src
| | - (etc)
| + App_Start
| + Model
| + Global.asax
| - Web.config
- ProjectTest
I have some URL rewrite rules so that any request website.com/x that doesn't refer to one of my Controllers will instead be redirected to website.com/AngularApp/dist/AngularApp/x. Everything I've described so far is working great.
The trouble is, this app is not being deployed to the root of the domain; it's being deployed to a subdirectory of the domain. (i.e. website.com/app instead of website.com). Three different portions of my app need to know that this new subdirectory should be considered root - the Angular app needs to have this configured as root, the rewrite rules need to incorporate this, and a certain pieces of C# code also needs to know about this new root (I'll save you the details here). Currently, I've had to specify this subdirectory in both the Pre Build Events (which are building the Angular app) and the Web.config (which controls my rewrite rules) and the Settings (which are accessed by my aforementioned C# code). It'd be better if I could have a single configuration that they all pulled from. My above question would at least allow the combination of two of these disparate three configurations.
My suggestion is not to do with any build events, it's rather to bootstrap your angular app with some values from hosting ASP view.
If I understand your app layout correctly, you might be able to push some variables onto a Razor view as plain javascript that would get picked up by Angular upon startup.
Model
public class SampleViewModel
{
public string Path { get; set; }
}
Controller
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
return View(new SampleViewModel() { Path = "/app/1/test" });
}
}
View
#model HelloWorldMvcApp.SampleViewModel
#{
Layout = null;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.min.js"></script>
</head>
<body>
<h1>Server-side path #Model.Path</h1>
<hr/>
<div ng-app="myApp">
<div ng-controller="MyController">
<h1>{{message}}</h1>
</div>
</div>
<script type="text/javascript">
var clientSidePath = "#Model.Path"; #* Razor happily renders values into javascript blocks *#
var app = angular.module('myApp', []);
app.controller('MyController', function($scope) {
$scope.message = 'Client-side path ' + clientSidePath;
});
</script>
</body>
</html>
The absolute minimum Dotnet fiddle here: https://dotnetfiddle.net/pO2wHN. For simplicity sake I opted for AngularJS (which is probably not the exact version you use) but similar approach should work with recent Angular as well.

Json get not working through azure but working locally

I have created a asp.net webapi and hosted it through azure.
This works fine when I run host/api/carparks. It also works when I run an ODATA query string
host/api/carparks?$Filter%20eq%20%27Liverpool%27
Google chrome returns the results as JSON as I want them.
The problem I am having is, I need to create a "Client" application to visualize my data. I have created a really simple for loop to return my data for testing purposes, once I have data returned I can start creating my application.
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
<script type="text/javascript">
function getStations() {
var town = document.getElementById("town").value;
var stationList = "<p>";
var uri = "http://localhost:38852/api/carparks?$filter=Town%20eq%20%27" + town + "%27";
$.getJSON(uri,
function (data) {
$('#here_data').empty(); // Clear existing text.
// Loop through the list of products.
$.each(data, function (key, val) {
stationList += val.Name + '<br />';
});
stationList += "</p>";
document.getElementById("here_data").innerHTML = stationList;
});
}
$(document).ready(getStations);
</script>
</head>
<body onload="getStations()">
<h1>Stations API</h1>
<p>Enter town</p>
<input type="text" id="town" value="Derby" />
<input type="button" value="Find Stations" onclick="getStations()" />
<div id="here_data">
<p>Car parks go here</p>
</div>
</body>
</html>
My client app works perfectly when I run my web api locally but when I change the getJSON request URI to my azure one (Which works in the browser!) nothing happens.
I have tried uploading my client app to azure and testing it that way but nothing :(
Is there any Azure settings that need to be changed?
Looks very much like a cross-origin issue.
The issue does not occur when you call the Service directly in your browser but only when you issue an Ajax call from a different domain (localhost vs. *.azurewebsites.net).
If you want to access your Web Api service with an Ajax call from a different domain you need to enable Cross Origin Resource Sharing (CORS).
A detailed article is found here:
http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api
Quoted from the link:
Install-Package Microsoft.AspNet.WebApi.Cors
Open the file App_Start/WebApiConfig.cs. Add the following code to the
WebApiConfig.Register method.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// New code
config.EnableCors();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Next, add the [EnableCors] attribute to the TestController class:
using System.Net.Http; using System.Web.Http; using
System.Web.Http.Cors;
namespace WebService.Controllers
{
[EnableCors(origins: "http://mywebclient.azurewebsites.net", headers: "*", methods: "*")]
public class TestController : ApiController
{
// Controller methods not shown...
}
}
For the origins parameter, use the URI where you deployed the
WebClient application. This allows cross-origin requests from
WebClient, while still disallowing all other cross-domain requests.
Later, I’ll describe the parameters for [EnableCors] in more detail.
Do not include a forward slash at the end of the origins URL.
Thanks to #viperguynaz and #florian I have fixed my issue. I changed the CORS option in Azure portal. (When I first did it I didn't remove the forward slash at the end of the URL). I removed the slash and it works.
I have also used the info given by #florian to help me understand CORS more.
Thanks again
1 happy joe :)

ASP.Net Boilerplate & jTable

I have studied the ASP.Net boilderplate template (http://www.aspnetboilerplate.com/Templates) and made some custom changes.
I have a "GetComponentDataList()" method in my services. I played around with that and rendered it as a list like shown here:
<!-- Component list -->
<ul class="list-group" ng-repeat="component in vm.components">
<div class="list-group-item">
<br />
<span>Entry:</span>
<span>{{component.entry}}</span>
</div>
</ul>
components.js code:
vm.refreshComponents = function () {
abp.ui.setBusy( //Set whole page busy until getComponentDataList complete
null,
componentDataService.getComponentDataList( //Call application service method directly from javascript
).success(function (data) {
vm.components = data.componentData;
})
);
};
Now I would like to render the components via jTable. jTable expects an action to get the list of data:
listAction: '/api/services/app/componentData/GetComponentDataList',
How do I use jTable from boilerplate template?
1. Do I need to add a method in my "HomeController" to use jTable?
2. The result of my "GetComponentDataList" method in my service is of type IOutputDto.
That means the result of my service is not directly a list. There is one indirection
level inbetween. Seems like this does not fit together.
3. Can I provide a function in my JS-ViewModel and use that function instead of an action URL?
Any hint would be awesome.
Thx.
I'm working on a sample project to work ABP with jTable. I did not finish it yet. But you can check it. https://github.com/aspnetboilerplate/aspnetboilerplate-samples/tree/master/AbpWithjTable
Add abp.jtable.js to your file (https://github.com/aspnetboilerplate/aspnetboilerplate-samples/blob/master/AbpWithjTable/AbpjTable.Web/App/Main/libs/abp.jtable.js) after all ABP and jtable scripts.
See example js: https://github.com/aspnetboilerplate/aspnetboilerplate-samples/blob/master/AbpWithjTable/AbpjTable.Web/App/Main/views/people/people.js
See example C# App service: https://github.com/aspnetboilerplate/aspnetboilerplate-samples/blob/master/AbpWithjTable/AbpjTable.Application/People/PersonAppService.cs

Resources