converted all auth functions to use mongoose
This commit is contained in:
0
client/css/.gitignore
vendored
0
client/css/.gitignore
vendored
@@ -1,51 +0,0 @@
|
||||
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
#cover {
|
||||
position:absolute;
|
||||
height:100%;
|
||||
width:100%;
|
||||
background:white;
|
||||
}
|
||||
|
||||
#userInfo {
|
||||
float:right;padding:8px;
|
||||
}
|
||||
|
||||
.icon-twitter {
|
||||
color:#00A7E7;
|
||||
}
|
||||
|
||||
.icon-facebook-sign {
|
||||
color:#3662A0;
|
||||
}
|
||||
|
||||
.icon-google-plus-sign {
|
||||
color: #D74634;
|
||||
}
|
||||
|
||||
.fade-hide-setup, .fade-show-setup {
|
||||
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
||||
-moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
||||
-o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
||||
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
||||
}
|
||||
|
||||
.fade-hide-setup {
|
||||
opacity:1;
|
||||
}
|
||||
.fade-hide-setup.fade-hide-start {
|
||||
opacity:0;
|
||||
}
|
||||
|
||||
.fade-show-setup {
|
||||
opacity:0;
|
||||
}
|
||||
.fade-show-setup.fade-show-start {
|
||||
opacity:1;
|
||||
}
|
0
client/img/.gitignore
vendored
0
client/img/.gitignore
vendored
@@ -1,71 +0,0 @@
|
||||
angular.module('myapp', ['ngCookies', 'ngRoute'])
|
||||
.config(['$routeProvider', '$locationProvider', '$httpProvider', function ($routeProvider, $locationProvider, $httpProvider) {
|
||||
var access = routingConfig.accessLevels;
|
||||
|
||||
$routeProvider.when('/', {
|
||||
templateUrl: 'home',
|
||||
controller: 'HomeCtrl',
|
||||
access: access.user
|
||||
});
|
||||
$routeProvider.when('/login', {
|
||||
templateUrl: 'login',
|
||||
controller: 'LoginCtrl',
|
||||
access: access.anon
|
||||
});
|
||||
$routeProvider.when('/register', {
|
||||
templateUrl: 'register',
|
||||
controller: 'RegisterCtrl',
|
||||
access: access.anon
|
||||
});
|
||||
$routeProvider.when('/private', {
|
||||
templateUrl: 'private',
|
||||
controller: 'PrivateCtrl',
|
||||
access: access.user
|
||||
});
|
||||
$routeProvider.when('/admin', {
|
||||
templateUrl: 'admin',
|
||||
controller: 'AdminCtrl',
|
||||
access: access.admin
|
||||
});
|
||||
$routeProvider.when('/404', {
|
||||
templateUrl: '404',
|
||||
access: access.public
|
||||
});
|
||||
$routeProvider.otherwise({
|
||||
redirectTo:'/404'
|
||||
});
|
||||
|
||||
$locationProvider.html5Mode(true);
|
||||
|
||||
var interceptor = ['$location', '$q', function($location, $q) {
|
||||
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(interceptor);
|
||||
}])
|
||||
.run(['$rootScope', '$location', 'Auth', function ($rootScope, $location, Auth) {
|
||||
$rootScope.$on("$routeChangeStart", function (event, next, current) {
|
||||
$rootScope.error = null;
|
||||
if (!Auth.authorize(next.access)) {
|
||||
if(Auth.isLoggedIn()) $location.path('/');
|
||||
else $location.path('/login');
|
||||
}
|
||||
});
|
||||
}]);
|
@@ -1,92 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* Controllers */
|
||||
|
||||
angular.module('angular-client-side-auth')
|
||||
.controller('NavCtrl', ['$rootScope', '$scope', '$location', 'Auth', function($rootScope, $scope, $location, Auth) {
|
||||
$scope.user = Auth.user;
|
||||
$scope.userRoles = Auth.userRoles;
|
||||
$scope.accessLevels = Auth.accessLevels;
|
||||
|
||||
$scope.logout = function() {
|
||||
Auth.logout(function() {
|
||||
$location.path('/login');
|
||||
}, function() {
|
||||
$rootScope.error = "Failed to logout";
|
||||
});
|
||||
};
|
||||
}]);
|
||||
|
||||
angular.module('angular-client-side-auth')
|
||||
.controller('LoginCtrl',
|
||||
['$rootScope', '$scope', '$location', '$window', 'Auth', function($rootScope, $scope, $location, $window, Auth) {
|
||||
|
||||
$scope.rememberme = true;
|
||||
$scope.login = function() {
|
||||
Auth.login({
|
||||
username: $scope.username,
|
||||
password: $scope.password,
|
||||
rememberme: $scope.rememberme
|
||||
},
|
||||
function(res) {
|
||||
$location.path('/');
|
||||
},
|
||||
function(err) {
|
||||
$rootScope.error = "Failed to login";
|
||||
});
|
||||
};
|
||||
|
||||
$scope.loginOauth = function(provider) {
|
||||
$window.location.href = '/auth/' + provider;
|
||||
};
|
||||
}]);
|
||||
|
||||
angular.module('angular-client-side-auth')
|
||||
.controller('HomeCtrl',
|
||||
['$rootScope', function($rootScope) {
|
||||
|
||||
}]);
|
||||
|
||||
angular.module('angular-client-side-auth')
|
||||
.controller('RegisterCtrl',
|
||||
['$rootScope', '$scope', '$location', 'Auth', function($rootScope, $scope, $location, Auth) {
|
||||
$scope.role = Auth.userRoles.user;
|
||||
$scope.userRoles = Auth.userRoles;
|
||||
|
||||
$scope.register = function() {
|
||||
Auth.register({
|
||||
username: $scope.username,
|
||||
password: $scope.password,
|
||||
role: $scope.role
|
||||
},
|
||||
function() {
|
||||
$location.path('/');
|
||||
},
|
||||
function(err) {
|
||||
$rootScope.error = err;
|
||||
});
|
||||
};
|
||||
}]);
|
||||
|
||||
angular.module('angular-client-side-auth')
|
||||
.controller('PrivateCtrl',
|
||||
['$rootScope', function($rootScope) {
|
||||
}]);
|
||||
|
||||
|
||||
angular.module('angular-client-side-auth')
|
||||
.controller('AdminCtrl',
|
||||
['$rootScope', '$scope', 'Users', 'Auth', function($rootScope, $scope, Users, Auth) {
|
||||
$scope.loading = true;
|
||||
$scope.userRoles = Auth.userRoles;
|
||||
|
||||
Users.getAll(function(res) {
|
||||
$scope.users = res;
|
||||
$scope.loading = false;
|
||||
}, function(err) {
|
||||
$rootScope.error = "Failed to fetch users.";
|
||||
$scope.loading = false;
|
||||
});
|
||||
|
||||
}]);
|
||||
|
@@ -1,55 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
angular.module('angular-client-side-auth')
|
||||
.directive('accessLevel', ['Auth', function(Auth) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function($scope, element, attrs) {
|
||||
var prevDisp = element.css('display')
|
||||
, userRole
|
||||
, accessLevel;
|
||||
|
||||
$scope.user = Auth.user;
|
||||
$scope.$watch('user', function(user) {
|
||||
if(user.role)
|
||||
userRole = user.role;
|
||||
updateCSS();
|
||||
}, true);
|
||||
|
||||
attrs.$observe('accessLevel', function(al) {
|
||||
if(al) accessLevel = $scope.$eval(al);
|
||||
updateCSS();
|
||||
});
|
||||
|
||||
function updateCSS() {
|
||||
if(userRole && accessLevel) {
|
||||
if(!Auth.authorize(accessLevel, userRole))
|
||||
element.css('display', 'none');
|
||||
else
|
||||
element.css('display', prevDisp);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
angular.module('angular-client-side-auth').directive('activeNav', ['$location', function($location) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function(scope, element, attrs) {
|
||||
var nestedA = element.find('a')[0];
|
||||
var path = nestedA.href;
|
||||
|
||||
scope.location = $location;
|
||||
scope.$watch('location.absUrl()', function(newPath) {
|
||||
if (path === newPath) {
|
||||
element.addClass('active');
|
||||
} else {
|
||||
element.removeClass('active');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}]);
|
@@ -1,97 +0,0 @@
|
||||
(function(exports){
|
||||
|
||||
var config = {
|
||||
|
||||
/* List all the roles you wish to use in the app
|
||||
* You have a max of 31 before the bit shift pushes the accompanying integer out of
|
||||
* the memory footprint for an integer
|
||||
*/
|
||||
roles :[
|
||||
'public',
|
||||
'user',
|
||||
'admin'],
|
||||
|
||||
/*
|
||||
Build out all the access levels you want referencing the roles listed above
|
||||
You can use the "*" symbol to represent access to all roles
|
||||
*/
|
||||
accessLevels : {
|
||||
'public' : "*",
|
||||
'anon': ['public'],
|
||||
'user' : ['user', 'admin'],
|
||||
'admin': ['admin']
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
exports.userRoles = buildRoles(config.roles);
|
||||
exports.accessLevels = buildAccessLevels(config.accessLevels, exports.userRoles);
|
||||
|
||||
/*
|
||||
Method to build a distinct bit mask for each role
|
||||
It starts off with "1" and shifts the bit to the left for each element in the
|
||||
roles array parameter
|
||||
*/
|
||||
|
||||
function buildRoles(roles){
|
||||
|
||||
var bitMask = "01";
|
||||
var userRoles = {};
|
||||
|
||||
for(var role in roles){
|
||||
var intCode = parseInt(bitMask, 2);
|
||||
userRoles[roles[role]] = {
|
||||
bitMask: intCode,
|
||||
title: roles[role]
|
||||
};
|
||||
bitMask = (intCode << 1 ).toString(2)
|
||||
}
|
||||
|
||||
return userRoles;
|
||||
}
|
||||
|
||||
/*
|
||||
This method builds access level bit masks based on the accessLevelDeclaration parameter which must
|
||||
contain an array for each access level containing the allowed user roles.
|
||||
*/
|
||||
function buildAccessLevels(accessLevelDeclarations, userRoles){
|
||||
|
||||
var accessLevels = {};
|
||||
for(var level in accessLevelDeclarations){
|
||||
|
||||
if(typeof accessLevelDeclarations[level] == 'string'){
|
||||
if(accessLevelDeclarations[level] == '*'){
|
||||
|
||||
var resultBitMask = '';
|
||||
|
||||
for( var role in userRoles){
|
||||
resultBitMask += "1"
|
||||
}
|
||||
//accessLevels[level] = parseInt(resultBitMask, 2);
|
||||
accessLevels[level] = {
|
||||
bitMask: parseInt(resultBitMask, 2),
|
||||
title: accessLevelDeclarations[level]
|
||||
};
|
||||
}
|
||||
else console.log("Access Control Error: Could not parse '" + accessLevelDeclarations[level] + "' as access definition for level '" + level + "'")
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
var resultBitMask = 0;
|
||||
for(var role in accessLevelDeclarations[level]){
|
||||
if(userRoles.hasOwnProperty(accessLevelDeclarations[level][role]))
|
||||
resultBitMask = resultBitMask | userRoles[accessLevelDeclarations[level][role]].bitMask
|
||||
else console.log("Access Control Error: Could not find role '" + accessLevelDeclarations[level][role] + "' in registered roles while building access for '" + level + "'")
|
||||
}
|
||||
accessLevels[level] = {
|
||||
bitMask: resultBitMask,
|
||||
title: accessLevelDeclarations[level][role]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return accessLevels;
|
||||
}
|
||||
|
||||
})(typeof exports === 'undefined' ? this['routingConfig'] = {} : exports);
|
@@ -1,62 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
angular.module('angular-client-side-auth')
|
||||
.factory('Auth', function($http, $cookieStore){
|
||||
|
||||
var accessLevels = routingConfig.accessLevels
|
||||
, userRoles = routingConfig.userRoles
|
||||
, currentUser = $cookieStore.get('user') || { username: '', role: userRoles.public };
|
||||
|
||||
$cookieStore.remove('user');
|
||||
|
||||
function changeUser(user) {
|
||||
_.extend(currentUser, user);
|
||||
};
|
||||
|
||||
return {
|
||||
authorize: function(accessLevel, role) {
|
||||
if(role === undefined)
|
||||
role = currentUser.role;
|
||||
|
||||
return accessLevel.bitMask & role.bitMask;
|
||||
},
|
||||
isLoggedIn: function(user) {
|
||||
if(user === undefined)
|
||||
user = currentUser;
|
||||
return user.role.title == userRoles.user.title || user.role.title == userRoles.admin.title;
|
||||
},
|
||||
register: function(user, success, error) {
|
||||
$http.post('/register', user).success(function(res) {
|
||||
changeUser(res);
|
||||
success();
|
||||
}).error(error);
|
||||
},
|
||||
login: function(user, success, error) {
|
||||
$http.post('/login', user).success(function(user){
|
||||
changeUser(user);
|
||||
success(user);
|
||||
}).error(error);
|
||||
},
|
||||
logout: function(success, error) {
|
||||
$http.post('/logout').success(function(){
|
||||
changeUser({
|
||||
username: '',
|
||||
role: userRoles.public
|
||||
});
|
||||
success();
|
||||
}).error(error);
|
||||
},
|
||||
accessLevels: accessLevels,
|
||||
userRoles: userRoles,
|
||||
user: currentUser
|
||||
};
|
||||
});
|
||||
|
||||
angular.module('angular-client-side-auth')
|
||||
.factory('Users', function($http) {
|
||||
return {
|
||||
getAll: function(success, error) {
|
||||
$http.get('/users').success(success).error(error);
|
||||
}
|
||||
};
|
||||
});
|
@@ -1,66 +0,0 @@
|
||||
!!! 5
|
||||
html(lang='en', data-ng-app='angular-client-side-auth')
|
||||
head
|
||||
meta(charset='utf-8')
|
||||
title Angular Auth Example
|
||||
link(rel='stylesheet', href='css/app.css')
|
||||
link(href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.no-icons.min.css", rel="stylesheet")
|
||||
link(href="//netdna.bootstrapcdn.com/font-awesome/3.1.1/css/font-awesome.min.css", rel="stylesheet")
|
||||
|
||||
// This is needed because Facebook login redirects add #_=_ at the end of the URL
|
||||
script(type="text/javascript").
|
||||
if (window.location.href.indexOf('#_=_') > 0) {
|
||||
window.location = window.location.href.replace(/#.*/, '');
|
||||
}
|
||||
body(data-ng-cloak)
|
||||
|
||||
.navbar(data-ng-controller="NavCtrl")
|
||||
.navbar-inner
|
||||
.container-fluid
|
||||
ul.nav
|
||||
li(data-access-level='accessLevels.anon', active-nav)
|
||||
a(href='/login') Log in
|
||||
li(data-access-level='accessLevels.anon', active-nav)
|
||||
a(href='/register') Register
|
||||
li(data-access-level='accessLevels.user', active-nav)
|
||||
a(href='/') Home
|
||||
li(data-access-level='accessLevels.user', active-nav)
|
||||
a(href='/private') Private
|
||||
li(data-access-level='accessLevels.admin', active-nav)
|
||||
a(href='/admin') Admin
|
||||
li(data-access-level='accessLevels.user')
|
||||
a(href="", data-ng-click="logout()")
|
||||
| Log out
|
||||
div#userInfo.pull-right(data-access-level='accessLevels.user')
|
||||
| Welcome
|
||||
strong {{ user.username }}
|
||||
span.label(data-ng-class='{"label-info": user.role.title == userRoles.user.title, "label-success": user.role.title == userRoles.admin.title}') {{ user.role.title }}
|
||||
|
||||
.container
|
||||
div(data-ng-view='ng-view')
|
||||
.alert.alert-error(data-ng-bind="error", data-ng-show="error")
|
||||
|
||||
script(src='http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js')
|
||||
script(src='https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js')
|
||||
script(src='https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular-cookies.min.js')
|
||||
script(src='https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular-route.min.js')
|
||||
script(src='/js/routingConfig.js')
|
||||
script(src='/js/app.js')
|
||||
script(src='/js/services.js')
|
||||
script(src='/js/controllers.js')
|
||||
script(src='/js/filters.js')
|
||||
script(src='/js/directives.js')
|
||||
|
||||
// Partial views... Load up front to make transitions smoother
|
||||
script(type="text/ng-template", id="404")
|
||||
include partials/404
|
||||
script(type="text/ng-template", id="admin")
|
||||
include partials/admin
|
||||
script(type="text/ng-template", id="home")
|
||||
include partials/home
|
||||
script(type="text/ng-template", id="login")
|
||||
include partials/login
|
||||
script(type="text/ng-template", id="private")
|
||||
include partials/private
|
||||
script(type="text/ng-template", id="register")
|
||||
include partials/register
|
0
client/views/partials/.gitignore
vendored
0
client/views/partials/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
h1 404
|
||||
p Ain't nothing here
|
@@ -1,20 +0,0 @@
|
||||
h1 Admin
|
||||
p This view is visible to users with the administrator role.
|
||||
|
||||
table.table.table-striped(data-ng-hide="loading")
|
||||
thead
|
||||
tr
|
||||
th #
|
||||
th Username
|
||||
th Role
|
||||
tbody
|
||||
tr(data-ng-repeat="user in users")
|
||||
td {{ user.id }}
|
||||
td
|
||||
i.icon-twitter(data-ng-show="user.provider == 'twitter'")
|
||||
i.icon-facebook-sign(data-ng-show="user.provider == 'facebook'")
|
||||
i.icon-google-plus-sign(data-ng-show="user.provider == 'google'")
|
||||
i.icon-linkedin(data-ng-show="user.provider == 'linkedin'")
|
||||
| {{ user.username }}
|
||||
td
|
||||
span.label(data-ng-class='{"label-info": user.role.title == userRoles.user.title, "label-success": user.role.title == userRoles.admin.title}') {{ user.role.title }}
|
@@ -1,2 +0,0 @@
|
||||
h1 Hello
|
||||
p This view is visible to logged in users.
|
@@ -1,42 +0,0 @@
|
||||
.hero-unit
|
||||
h1 Log in
|
||||
p This site is an example of how one can implement role based authentication in Angular applications as outlined in
|
||||
a(href="http://www.frederiknakstad.com/authentication-in-single-page-applications-with-angular-js/") this blogpost
|
||||
| . All the code can be found in
|
||||
a(href="https://github.com/fnakstad/angular-client-side-auth") this GitHub repository
|
||||
| . You can either register a new user, log in with one of the two predefined users...
|
||||
ul
|
||||
li admin/123
|
||||
li user/123
|
||||
form.form-horizontal(ng-submit="login()", name="loginForm")
|
||||
.control-group
|
||||
label.control-label(for="username") Username
|
||||
.controls
|
||||
input(type="text", data-ng-model="username", placeholder="Username", name="username", required, autofocus)
|
||||
.control-group
|
||||
label.control-label(for="password") Password
|
||||
.controls
|
||||
input(type="password", data-ng-model="password", placeholder="Password", name="password", required)
|
||||
.control-group
|
||||
.controls
|
||||
label(for="rememberme").checkbox
|
||||
input(type="checkbox", data-ng-model="rememberme", name="rememberme")
|
||||
| Remember me
|
||||
.control-group
|
||||
.controls
|
||||
button.btn(type="submit", data-ng-disabled="loginForm.$invalid") Log in
|
||||
hr
|
||||
p ... or use one of them fancy social logins:
|
||||
.btn-group
|
||||
a.btn(href="", data-ng-click="loginOauth('facebook')")
|
||||
i.icon-facebook-sign
|
||||
| Facebook
|
||||
a.btn(href="", data-ng-click="loginOauth('twitter')")
|
||||
i.icon-twitter
|
||||
| Twitter
|
||||
a.btn(href="", data-ng-click="loginOauth('google')")
|
||||
i.icon-google-plus-sign
|
||||
| Google
|
||||
a.btn(href="", data-ng-click="loginOauth('linkedin')")
|
||||
i.icon-linkedin
|
||||
| LinkedIn
|
@@ -1,2 +0,0 @@
|
||||
h1 Private view
|
||||
p This view is visible to logged in users
|
@@ -1,30 +0,0 @@
|
||||
h1 Register
|
||||
form.form-horizontal(ng-submit="register()", name="registerForm")
|
||||
.control-group
|
||||
label.control-label(for="username") Username
|
||||
.controls
|
||||
input(type="text", data-ng-model="username", placeholder="Username", name="username", required, data-ng-minlength="1", data-ng-maxlength="20", autofocus)
|
||||
.control-group
|
||||
label.control-label(for="password") Password
|
||||
.controls
|
||||
input(type="password", data-ng-model="password", placeholder="Password", name="password", required, data-ng-minlength="5", data-ng-maxlength="60")
|
||||
.control-group
|
||||
label.radio.inline
|
||||
input(type="radio", name="role", data-ng-model="role", id="adminRole", data-ng-value="userRoles.admin")
|
||||
| Administrator
|
||||
label.radio.inline
|
||||
input(type="radio", name="role", data-ng-model="role", id="adminRole", data-ng-value="userRoles.user")
|
||||
| Normal user
|
||||
.control-group
|
||||
.controls
|
||||
button.btn(type="submit", data-ng-disabled="registerForm.$invalid") Submit
|
||||
|
||||
.alert.alert-error(ng-show="registerForm.$invalid && registerForm.$dirty")
|
||||
strong Please correct the following errors:
|
||||
ul
|
||||
li(ng-show="registerForm.username.$error.required") Username is required
|
||||
li(ng-show="registerForm.username.$error.minlength") Username has to be at least 1 character long
|
||||
li(ng-show="registerForm.username.$error.maxlength") Username has to be at most 20 character long
|
||||
li(ng-show="registerForm.password.$error.required") Password is required
|
||||
li(ng-show="registerForm.password.$error.minlength") Password must be at least 5 characters long
|
||||
li(ng-show="registerForm.password.$error.maxlength") Password must be at most 60 characters long
|
Reference in New Issue
Block a user