refreshing user.is_authenticated with angular and django rest framework - angularjs

I'm using django rest framework on the backend and angularjs on the frontend. The problem is the login, in angular I do:
function ($scope, $http, User) {
$scope.login = function (user) {
$http.post('/login/', user)
.then(function (response, status) { // success callback
console.log("success");
console.log(response);
}, function(response) { // error callback
console.log("error");
console.log(response);
})
}
}
then in my views.py I do:
def login_view(request):
user = authenticate(username=request.data['username'], password=request.data['password'])
if user is not None:
login(request, user)
return HttpResponse(status=200)
return HttpResponse(status=400)
But in my home template which is the only django template that I use, the rest is pure html since I use ui-router with state view, so the {% if user.is_authenticated %} won't get updated and I have to refresh the page manually. Is there any solution to make the 'if' statement in the template to be trigger without refreshing all the page, or any better solution to make a login system in my website?
Thank you.

You should not use Django's templatescripts in AngularJS.
AngularJS is a SPA. Django's templatescripts does not work well with SPAs.
You need to create your client logic in javascript only.
This can be done by creating a server endpoint that returns true if a given user is authenticated.

Related

How to redirect users to another page with Angular routing if the API controller has Authorize attribute?

I have such Api action method:
[Authorize(Roles = "Admin")]
[HttpGet, Route("")]
public List<TaskViewModel> GetAll()
{
return TasksRepository.SelectAll(Context);
}
and using angular to fetch data through some http service;
and have this routing configuration:
$routeProvider.when('/Tasks', {
title: 'Tasks',
controller: 'tCtrlr',
templateUrl: '../HTML/Tasks.html',
})
The problem with that approach is that I cant notify the user that he is getting an empty data because he is not authorized to view its content?
so I want to show a message or redirect him to another page, if the API action has Authorize attribute, that the user must be logged in or he cannot view the contents of the page?
You"ll have to check the response header ..
If the status is 401 (unauthorized) then handle the redirection or else
Try something like this
$http("api/yourAPI")
.then(function (success) { ... } ,
function (error) {
if (error.status==401) {
// handle unauthorised
}
});
I'm not quite sure about syntax but you got the idea
Edit for Refrence
Check this for more clear syntax but keep in mind that .success .error are deprecated in angularjs latest version

Angular.js SPA security with ASP.NET MVC and WebApi

I'm building a SPA using Angular.js and ASP.NET and I would like to know what is the best way to secure it.
Here is what I need :
I would like to use MVC framework to hide my application only to logged users. So the first thing that users will do before launching the SPA will be to log into the website using a simple login form.
When the Angular app will be launched, it will communicate with my ApiController using REST requests.
I also want my user to be logged out automatically after 20 minutes of inactivity.
I know that REST is supposed to be stateless... but I can't figure how to implement all I need without sessions...
But on the other side, I want to be able to use my WebAPI with a future mobile application. I will have to use Tokens for the authentication on this application.
What is the best way for me to achieve that kind of authentication?
Thanks for your time!
I developed an entire security layer with the same conditions as yours following those very well explained in this post here.
BTW, the token will expire automatically after 20 minutes because when you create it you will set it's expiration date immediately; every time you're going to make a request, the system will check the token exp date with the current date, refusing your token if the time passed. For example this a tipical oauth server configuration with token and refresh token settings:
internal static OAuthAuthorizationServerOptions GetAuthorizationServerOptions(IComponentContext scope)
{
OAuthAuthorizationServerOptions oAuthServerOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
ApplicationCanDisplayErrors = true,
TokenEndpointPath = new PathString(Constants.PublicAuth.OAUTH_TOKEN_PATH),
AuthorizeEndpointPath = new PathString(Constants.ExternalAuth.AUTH_ENDPOINT),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(Constants.PublicAuth.TOKEN_EXPIRATION_IN_MINUTES),
Provider = scope.Resolve<AuthorizationServerProvider>(),
AccessTokenFormat = new CustomJwtFormat(),
RefreshTokenProvider = scope.Resolve<SimpleRefreshTokenProvider>()
};
return oAuthServerOptions;
}
The refresh token is also very useful, but you have to manage the token replacement by yourself; for example in our application we pass every API call through a single service that, if the server responds 401 (unauthorized), it will try to request a new token using the refresh token and then it will try the same call again. Only after the second failure you'll be redirected to the login page.
For example:
function executeCallWithAuth(method, url, payload, params) {
var defer = $q.defer();
debug.logf('{0}: {1}', method.toUpperCase(), url);
$http({ method: method, url: url, data: payload, headers: createHeaders(), params: params }).then(
function(results) { defer.resolve(results); },
function(error) {
if (error.status !== 401) defer.reject(error);
else {
debug.warn(`Call to: ${method}:${url} result in 401, try token refresh...`);
auth.refreshToken().then(
function() {
debug.warn('Token refresh succesfully, retry api call...');
$http({ method: method, url: url, data: payload, headers: createHeaders() }).then(
function(results) { defer.resolve(results); },
function(errors) { defer.reject(errors); });
},
function(tokenError) {
debug.warn('Token refresh rejected, redirect to login.');
$state.go('login');
defer.reject(tokenError);
});
}
});
return defer.promise;
}
and
function createHeaders() {
var headers = {
};
var authData = storage.get('authorizationData');
if (authData) {
headers.Authorization = 'Bearer ' + authData.token;
}
return headers;
}
Using Angular the best way to secure a route is "do not create a route". Basically, you need to load the user profile, and only after that you will create the routes only to the pages he can navigate to. If you don't create the route for a page you don't need to secure that page: Angular will automatically send the user to a 404.
I would secure your WebAPI calls with OAuth2 (you can even use the built in Identity 2.0 provider that comes baked in with it). Keep your WebAPI stateless, use SSL (consider a filter to force it), and use the [Authorize] tags to secure you services. On the MVC side, this will have to maintain state and you will want to have the login form get an OAuth2 token from your WebAPI layer and pass that down into Angular. Set the expiration on this to 20 minutes. You can also use the cookies authentication model here since it will need to be stateful on the MVC side, but all ajax calls made to the WebAPI layer by Angular will need to pass the OAuth2 token as a bearer token in the Authorization request header.

Node API - How to link Facebook login to Angular front end?

Rewriting this question to be clearer.
I've used passport-facebook to handle login with facebook on my site.
My front end is in Angular so I know now need to understand whats the correct way of calling that api route. I already have several calls using Angular's $http service - however as this login with facebook actually re-routes the facebook page can i still use the usual:
self.loginFacebook = function )() {
var deferred = $q.defer();
var theReq = {
method: 'GET',
url: API + '/login/facebook'
};
$http(theReq)
.then(function(data){
deferred.resolve(data);
})
return deferred.promise;
}
or is it perfectly ok/secure/correct procedure to directly hit that URL in a window location:
self.loginFacebook = function (){
$window.location.href = API + '/login/facebook';
}
Furthermore, from this how do I then send a token back from the API? I can't seem to modify the callback function to do that?
router.get('/login/facebook/callback',
passport.authenticate('facebook', {
successRedirect : 'http://localhost:3000/#/',
failureRedirect : 'http://localhost:3000/#/login'
})
);
Thanks.
I was stacked on the same problem.
First part:
I allow in backend using cors and in frontend i use $httpProvider, like this:
angular.module('core', [
'ui.router',
'user'
]).config(config);
function config($httpProvider) {
$httpProvider.defaults.useXDomain = true;
$httpProvider.defaults.headers.common['X-Requested-With'];
$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
};
The second part:
<span class="fa fa-facebook"></span> Login with facebook
This call my auth/facebook route that use passport to redirect to facebook page allowing a user to be authenticated.
If the user grant access, the callback /api/auth/facebook/callback is called and the facebook.strategy save the user with the profile data.
After saving the user, i create a special token with facebook token, id and email. This info is used to validate every time the user access to private states in the front.
My routes are something like this:
router.get('/facebook', passport.authenticate('facebook',
{ session: false, scope : 'email' }));
// handle the callback after facebook has authenticated the user
router.get('/facebook/callback',
passport.authenticate('facebook',
{session: false, failureRedirect: '/error' }),
function(req, res, next) {
var token = jwt.encode(req.user.facebook, config.secret);
res.redirect("/fb/"+token);
});
In frontend i catch the /fb/:token using a state and assign the token to my local storage, then every time the user go to a private section, the token is sent to backend and validate, if the validation pass, then the validate function return the token with the decoded data.
The only bad thing is that i don't know how to redirect to the previous state that was when the user click on login with facebook.
Also, i don't know how you are using the callback, but you need to have domain name to allow the redirect from facebook. I have created a server droplet in digitalocean to test this facebook strategy.
In the strategy you have to put the real domain in the callback function, like this:
callbackURL: "http://yourdomain.com/api/auth/facebook/callback"
In the same object where you put the secretId and clientSecret. Then, in your application in facebook developers you have to allow this domain.
Sorry for my english, i hope this info help you.
Depending on your front-end, you will need some logic that actually makes that call to your node/express API. Your HTML element could look like
<a class='btn' href='login/facebook'>Login</a>
Clicking on this element will make a call to your Express router using the endpoint of /login/facebook. Simple at that.

How to route a specific JSP using AngularJS

I am new to AngularJS. I have the code below and need to redirect it to a different JSP if the service is success
$scope.User = $resource('anc/validUser', data)
.get().$promise.then(
function(response){
console.log('success');
$location.path('/home');
}, function() {
console.log('error');
});
I was using $location and I am not sure if that is a valid one. Can someone guide me to understand how to route to a different JSP. I have a login.jsp and after the authentication validation through a REST service, I need to take the user to home.jsp

How do you load data asynchronously when loading an angular module?

In my angular app I need to read some data from the server before I allow the rest of my application to run. For example, I need the user authenticated so I can verify their permission before I allow them access to anything. Since I need to do this on app start and I don't know what controller will be loaded first, I can't use the resolve feature of the $routeProvider.when method because I do not know which controller will be hit first, and it only occurs once on app start.
I keep steering towards doing something in the module.run method, but I can't find a way to prevent it from continuing until get the data back from the server. I found this but it suffers from the same problem: AngularJS : Initialize service with asynchronous data.
I can also do manual bootstrapping, but I can't find any good examples of how to do this. Any help you can provide would be appreciated.
The easiest way i can think of here would be to have a separate page for login. Once the user is authenticated then only allow him access to the main app (angular app).
Also you need to secure you service resources against unauthorized request. This would safeguard against your controller \ views loading unauthorized data.
Like the other answer already mentioned, you should take care of the security of your app.
Possible solutions are:
Check if the user is authenticated
Implement a authentication in your API. You can check if the user is logged in with a responseInterceptor:
.config(['$routeProvider','$httpProvider', function($routeProvider,$httpProvider) {
//setup your routes here...
var authChecker = ['$location', '$q', function($location, $q) {
//redirects the user to /login page if he's not authorized (401)
function success(response) {
return response;
}
function error(response) {
if(response.status === 401) {
$location.path('/login');
return $q.reject(response);
}
else {
return $q.reject(response);
}
}
return function(promise) {
return promise.then(success, error);
}
}];
$httpProvider.responseInterceptors.push(authChecker);
}])
See $http docs for more details.
Workaround: run scope
Does not solve the security issues, but is working, too:
Get your data in the run block like this:
.run(function($http,$location,$rootScope) {
$rootScope.$on("$routeChangeStart", function (event, next, current) {
if($rootScope.gotData) {
$location.path(next.path);
} else {
$location.path('/loading');
}
});
$http.get('path/to/data').success(function() {
$rootScope.gotData = true;
$location.path('/home');
}).error(function() {
$location.path('/404');
})
})
see docs for further information.

Resources