Can I or Should I use a Global variable in Angularjs to store a logged in user? - node.js

I'm new to angular and developing my first 'real' application. I'm trying to build a calendar/scheduling app ( source code can all be seen on github ) and I want to be able to change the content if there is a user logged in (i.e. display details relevant to them) but here's the catch:
I don't want the app to be dependent on having a logged in user ( needs to be something that can be configured to work publicly, privately or both)
I don't want to implement the user/login within this app if it can be avoided ( I want to eventually include my app in another app where this might be implemented but isn't necessarily implemented using any particular security frameworks or limited to any)
I had an idea of creating some global variable user that could be referenced through out my application, or if I had to implement a system to do it all in this app that I could do so in in some abstract way so that different options could be injected in.
some of my ideas or understanding of what I should be doing may be completely wrong and ignorant of fundamentals but I genuinely do not know what approach I should take to do this.
In case it is relevant I currently don't have any back-end but eventually hope use MongoDB for storage and nodejs for services but I also want to try keep it open-ended to allow others to use different storage/backends such as sql and php
is there away to have a global uservariable/service that I could inject/populate from another (parent?) app?
If so what would be the best approach to do so?
If Not, why and what approach should I take and why?
Update
I Believe from comments online and some suggestion made to me that a service would be the best option BUT How would I go about injecting from a parent application into this applications service?

If your (single) page is rendered dynamically by the server and the server knows if you are logged-in or not, then you could do the following:
Dynamically render a script tag that produces:
<script>
window.user = { id: 1234, name: 'User A', isLoggedIn: true };
</script>
For non logged-in users:
<script>
window.user = { isLoggedIn: false };
</script>
For convinience, copy user to a value inside angular's IOC:
angular.module('myApp').value('user', window.user);
Then, you can use it in DI:
angular.module('myApp').factory('myService', function(user) {
return {
doSomething: function() {
if (user.isLoggedIn) {
...
} else {
...
}
}
};
});
Something tricky (which you should thing twice before doing [SEE COMMENTS]) is extending the $scope:
angular.module('myApp').config(function($provide) {
$provide.decorator('$controller', function($delegate, user) {
return function(constructor, locals) {
locals.$scope._user = user;
return $delegate(constructor, locals);
};
});
});
This piece of code decorates the $controller service (responsible for contructing controllers) and basically says that $scope objects prior to being passed to controllers, will be enhanced with the _user property.
Having it automatically $scoped means that you can directly use it any view, anywhere:
<div ng-if="_user.isLoggedIn">Content only for logged-in users</div>
This is something risky since you may end up running into naming conflicts with the original $scope API or properties that you add in your controllers.
It goes without saying that these stuff run solely in the client and they can be easily tampered. Your server-side code should always check the user and return the correct data subset or accept the right actions.

Yes you can do it in $rootScope. However, I believe it's better practice to put it inside a service. Services are singletons meaning they maintain the same state throughout the application and as such are prefect for storing things like a user object. Using a "user" service instead of $rootScope is just better organization in my opinion. Although technically you can achieve the same results, generally speaking you don't want to over-populate your $rootScope with functionality.

You can have a global user object inside the $rootScope and have it injected in all your controllers by simply putting it into the arguments of the controller, just as you do with $scope. Then you can implement functionalities in a simple check: if($rootScope.user). This allows you to model the user object in any way you want and where you want, acting as a global variable, inside of Angular's domain and good practices with DI.

Just to add on my comment and your edit. Here is what the code would look like if you wanted to be able to re-use your user service and insert it into other apps.
angular.module('user', []).service('userService', [function(){
//declare your user properties and methods
}])
angular.module('myApp', ['user'])
.controller('myCtrl', ['userService', '$scope', function(userService, scope){
// you can access userService from here
}])
Not sure if that's what you wanted but likewise you could have your "user" module have a dependency to another "parent" module and access that module's data the same way.

Related

Clean Architecture - How to handle usecase dependencies

I am refactoring one of my older applications around to using the concept of use cases "clean architecture".
I am little confused on how to leverage the common data & entity validations
for e.g. There are 2 use cases
Allow admins to import a new workflow template
Allow admins to create new workflow template
The above use cases are called from the controllers.
In both the above cases, there are some common database level validations like:
Is there already a workflow with same name ?
To handle these validations, Do I make this as separate use-case like "checkIfWorkflowWithSameNameExists()" ?
If I make a separate use case, then what options are better to call these common validations
Can one use case call another use case directly
export function importNewWorkflowTemplate(specs){
const { workflowRepository } = specs;
const exists = checkIfWorkflowWithSameNameExists()
if(exists){
//return error
}
return new (payLoad) => {
//logic
}
}
Should I be injecting the dependent use cases
export function importNewWorkflowTemplate(specs){
const { workflowRepository, checkIfWorkflowWithSameNameExists } = specs;
return new (payLoad) => {
//logic
}
}
Should the validation belong to outer layer like the controller?
What you describe - checkIfWorkflowWithSameNameExists() - is not a use case.
This is simply a method put on a domain service, such as a repository. This could be a repository method on your workflow repository such as hasWorkflowWithName(name). The repository represents a collection of aggregates and thus knows best if there is one with the same name already.
If there is more complex domain logic to check for an existing repository and then either perform some error handling or performing specific logic to create the logic you can also consider to encapsulate these steps inside a domain service method. In this case the workflow repository interface would be injected into the workflow domain service which would then again be injected into the use cases.
With that you could use the same domain service in both use cases and the use case are responsible to orchestrate the translation between the external commands and the domain service interface and the corresponding domain entities.

How safe is front end with react and redux?

I am wondering this for a while now when I am building react and redux applications. How easy is it for a person to change the redux and/or react state manually? I can't find documentation on this anywhere and would love to know the security issues etc.
Example of a redux state
{
firstName: 'Foo',
lastName: 'Bar',
permissions: {
'admin': false
}
}
Would they be able to change or influence something like the admin permission and set it to true?
And if they can change it, would it be accepted by reducers etc?
The frontend is inherently insecure. I can inject my own code any time. Setup breakpoints and manipulate variables during runtime.
With that in mind. I could put anything I wanted in a redux store and get any value out of it. This includes setting an admin permission/flag to true.
I could also trigger the reducers to run with the new value.

What is a good pattern for implementing access control in a GraphQL server?

Background:
I have a set of models, including a User and various other models, some of which contain references to a User. I am exposing these models for querying via a GraphQL API generated by Graffiti, backed by a Mongo database using the graffiti-mongoose adaptor. My current REST API (which I am migrating to GraphQL) uses JSON Web Tokens to authenticate users, and has some custom permission logic on the server side to handle access control.
Problem:
I'd like to restrict access to objects in GraphQL based upon the current logged-in user. Some models should be accessible for reads by unauthenticated calls. Most other models should be only accessible to the User who created them. What's the best way to manage access control to objects via the Graffiti-generated API?
In general, are there good patterns of access control for GraphQL? And in particular, are there any good examples or libraries for doing it with Graffiti?
Notes:
I understand that pre- and post- hooks have been implemented for graffiti-mongoose, and that they can be used to do basic binary checks for authentication. I'd like to see how a more detailed access-control logic could be worked into a GraphQL API. In the future, we'll want to support things like Administrators who have access to model instances created by a certain group of Users (e.g. Users whose Affiliations include that of the Administrator).
Typically GraphQL does not handle access control directly, instead delegating that responsibility to whatever data system it interfaces with. In your case that sounds like Mongoose.
Since access control logic is often arbitrary logic (for example, has this user been banned from some content? did the publisher of that content restrict it with custom privacy settings? etc.), and it sounds like in your case this access control logic is in fact custom, it should live in the "resolve" function which produces a value for a GraphQL field.
For example:
var UserType = new GraphQLObjectType({
name: 'User',
fields: {
name: { type: GraphQLString },
birthday: {
type: GraphQLString,
resolve(user, context) {
var auth = context.myLoggedInAuth;
if (myCanAuthSeeBirthday(auth, user)) {
return user.birthday;
}
}
}
}
});
I create a rule base access control to be used with GraphQL.
https://github.com/joonhocho/graphql-rule
It is simple and unopionated that it can be used with or without GraphQL.
You can use it with a plain javascript objects.
Hope it helps GraphQLers!

CRUD blueprint overriding in sails.js

According to this closed issue in sails:
https://github.com/balderdashy/sails/issues/835
CRUD Blueprint Overrides
"absolutely, this is coming in v0.10"
I'd like to modify the blueprints in my sailsjs service to allow named roots (consuming in ember).
Currently I'm having to customize every controller I create with actions that are largely duplicates of what is already in the blueprints.
I suspect that I can move this code out of my controllers now and into a blueprints override area, but I'm not clear on where to put that code.
Any examples or even just a pointer to the relevant code in sails the .10 repo would be greatly appreciated.
Update
In order to override blueprints in Sails 1.0 in the manner described below, you must first install the "custom blueprints" plugin for your project (npm install sails-hook-custom-blueprints).
To override blueprints in Sails v0.10, you create an api/blueprints folder and add your blueprint files (e.g. find.js, create.js, etc.) within. You can take a look at the code for the default actions in the Sails blueprints hook for a head start.
Adding custom blueprints is also supported, but they currently do not get bound to routes automatically. If you create a /blueprints/foo.js file, you can bind a route to it in your /config/routes.js file with (for example):
'GET /myRoute': {blueprint: 'foo'}
you can add actions with these names inside your controller to override default behaviour
to change destroy behavior
module.exports = {
destroy: function(req,res){
Goal.update({ id: req.param('id') }, { deleted: true })
.exec(function (err, goal) {
if (err) return res.json(err, 400);
return res.json(goal[0]);
});
}
}
It is possible to use the build in blueprints, but with policies running first. These policies might verify that the user is logged in, has the correct access, or similar. Really handy!
On each model, you have available callbacks both before and after data has been stored. Dig in: http://sailsjs.com/documentation/concepts/models-and-orm/lifecycle-callbacks
There is no default callback available for blueprints result. But don't give up. It is still possible to use the build in blueprints, and only modify the output. It might not be the most elegant solution, but it works well. Check out my “hack” here: Sails blueprints lifecycle

How to modularize AngularJS applications / plugins

I have a couple of (software-)architecture questions regarding a migration from Grails (REST-API, parts of AngularJS, MongoDB, Tomcat, Spock, several plugins) to Node.js + Angular.js.
I probably have to explain the structure of the Grails project fist, so here we go:
There is a main Grails application (beside a couple of other applications), which is built on several plugins. Each of these plugins is able to get executed by itself - that means it has its own UI, individual templates, services, controllers, routes, tests etc. It is also hosted on different repositories.
This is done by the Grails plugin mechanisms. The benefits are less testing-efforts, less compiling time, modularization, single responsibilities and so on.
But still, the time to compile and test are too expensive. Also I don't like the fact that the API delivers parts of the templates/views. I would like to have the backend APIs "just to be backend APIs" and the frontend "just to be the frontend".
So each AngularJS application/plugin will provide its own view, routes, service etc. But they might also depend on other plugins.
So what I would like to achieve is as follow:
One main AngularJS application, which includes several plugins (a plugin can be something like a report-generator, a guestbook or whatsoever, speaking of a single independent part of an application, either with a specific route, or just a small part of the page).
Each plugin must be a stand-alone AngularJS application (probably executable during development via grunt or so). So that the UI developer does not need to start the whole backend application, further that we may run functional tests only with JavaScript
Communication only via REST, The frontend must retrieve all it's data from the APIs
Each plugin must be testable on its own
A Plugin might require other plugins to work
The main index.html (and app.js?) might be provided by a Nginx server, which is decoupled from the rest of the backend (API)
Though I have a specific picture in my head, I am struggling in how to setup this architecture.
In Grails the plugin mechanisms are somehow merging the plugin dependant settings (like URL mappings, dependencies, etc) to the main application in which they get included/injected - this is what I want to achieve with AngularJS as well. So:
Are there some kind of same mechanisms for AngularJS?
How may I provide/merge the routes of each plugin into the main application?
How can I declare application- and plugin-dependencies?
What tools might be usefull for the build process?
How to establish lazy-retrievments of the plugin-resources (css/less files, views, services etc)?
Prevent the application to provide all resources of the plugins on startup (I guess the routes are required on startup though)
Since this is not just a how-to-do-this-or-that question I excuse myself if I am missing important parts or if some parts are not clear enough. Just ask me and I will answer each question in depths.
** This answer is incomplete **
I want to make sure I understand you before I dig into this.
Here's a quick implementation of a Loader module to manage lazy loading (plugins, vendor assets, admin stuff etc).
Does this help?
angular.module('Bizcoin.loader')
.service('Loader', Loader);
function Loader($injector, $ocLazyLoad, User) {
var Loader = {
load: load,
get: get,
plugins: {},
flags: {}
};
init();
return Loader;
function init() {
load('vendors');
if (userIsAdmin)
load('admin');
}
function load(plugin) {
Loader.plugins[plugin] = Loader[plugin] || $ocLazyLoad.load('path/to/'+plugin+'.js');
return Loader.plugins[plugin].then(setFlag);
function setFlag() {
return Loader.flags[plugin] = true;
}
}
function get(plugin) {
return load(plugin).then(function() {
return $injector.get(plugin);
});
}
}
I work on an large .Net/AngularJS application that is composed of 20+, independent, Areas (or modules) and some core functionality common and reused across all Areas.
Let me go into detail on how I do this for my particular case, and it might give some ideas. The fact that I use .Net is irrelevant here, since this can achieve with any framework.
Each Area acts as an independent application that depends only on the core functionality, always present. Each Area has its own ASP.Net MVC route.
Each Area registers with the core application the menu links it wants to provide.
When the customer goes to the application dashboard, only the core part of of the application. When the user clicks on link in the menu, it will navigate to the content provided by one of the Areas, and only the core plus the assets of that Area are loaded.
Lets see how this is done.
In the main page of the application I load the scripts like this:
<script type="text/javascript">
// a JS object with all the necessary app data from the server.
// e.g.: menu data, etc
window.appContext = #Html.Action("ApplicationContext", "Portal"));
</script>
#Scripts.Render("~/bundles/angular-main")
#RenderSection("AngularAreas", required: false)
I make use of dot .Net bundles and sections.
The main (core) AngularJS part of the application consists of angular configuration, internationalization services, global notifications service, reusable UI components, etc. This is loaded is #Scripts.Render("~/bundles/angular-main").
The #RenderSection("AngularAreas", required: false) section will be filled in by each area when the user navigates to that Area.
Lets see some AngularJS code.
Here is part of the main app.ts.
// If user is visiting an Area, the NgModules array will be augmented.
// with the modules the Area wants to provide (to be bootstrapped)
export var LoadNgModules = [
NgModules.Config,
NgModules.Core
];
angular.module(NgModules.Bootstraper, LoadNgModules);
angular.element(document).ready(function () {
angular.bootstrap(document, [NgModules.Bootstraper]);
});
Lets look at an example Area now.
And here is how an Area would supply its assets, to be outputted in #RenderSection("AngularAreas", required: false):
#section AngularAreas {
#Scripts.Render("~/bundles/areas/staff-management")
}
Its a simple bundle containing all the scripts for that Area.
Now, let's see the important part of the AngularJS code for this Area.
var StaffManagementNgModule = 'areas.staff-management';
// Push our self into the modules to be bootstrapped
LoadNgModules.push(StaffManagementNgModule );
// Define the module
angular
.module(StaffManagementNgModule , ['ngRoute', NgModules.Core])
.config([
'$routeProvider', '$locationProvider', ($routeProvider: ng.route.IRouteProvider, $locationProvider) => {
$routeProvider
.when(staff', { template: '<staff></staff>' })
.when('staff/details/:id', { template: '<staff-details></staff-details>' });
}
]);;
That is all, from here the Area is a normal Angular application.
To summarize, we load the main (core) AngularJS functionality and provide the LoadNgModules array that an area can fill with its own modules.
we load the Area scripts and and "our self" to the LoadNgModules array.
finally the run angular.bootstrap.
For completeness, here is a fragment of C# showing how an area would indicate to the main application that it is available
public class ItemManagementModuleRegistration : IModuleRegistration
{
public void Register(ModuleContext moduleContext)
{
string thisAreaName = "Staff";
moduleContext.RegisterMenu(menuContext =>
{
var ItemsMenu = menuContext.Items(thisAreaName);
// add urls and stuff...
});
// register more stuff with the moduleContext
}
}
Using reflection one can easily find what areas are "installed".
These are the main moving parts of the setup.
Each Area can have its own API and tests. It is quite flexible.

Resources