Trying to get login required to work when trying t

2019-08-23 15:03发布

  • Django 1.11
  • Django REST Framework (DRF) 3.6
  • DRF-JWT 1.10
  • AngularJS 1.6.5
  • ui-router 1.0.3

Fairly new to all of this technology and have been messing with this issue for several days now. Learned about this stack (minus UI-router which I just switched to a week ago) through the following class and repository:

https://www.udemy.com/django-angularjs/learn/v4/overview

https://github.com/codingforentrepreneurs/Django-AngularJS/tree/master/src

These are the directories that are probably the most relevant to my issue:

Config and JS: https://github.com/codingforentrepreneurs/Django-AngularJS/tree/master/src/static/js/app

Login-required interceptor: https://github.com/codingforentrepreneurs/Django-AngularJS/tree/master/src/static/js/app/core/interceptors

Service, pages where login is required, and interceptor is utilized: https://github.com/codingforentrepreneurs/Django-AngularJS/tree/master/src/static/js/app/core/comment

I am trying to adapt it for my project.

I have read several tutorials on using ui-router purely for this purpose, but they don't seem to use DRF-JWT or are missing important steps that a newb like me needs.

Anyway, I have two urls:

/

/dashboard

The former is the login, /dashboard requires authorization and should route to / if the person isn't logged in. Before I started trying to implement this, one could just type in /dashboard without being authenticated and view it. I have verified that when a person logins in the token through DRF-JWT it is being generated and written to the cookie as I can console.log it on successful login.

Since I have been trying to implement this, I can't even get / to load. I get an $injector:modulerr issue that I can't resolve.

Code time:

I get the $injector:modulerr once I change:

// dashboard.module.js

angular.module('dashboard', ['chart.js']);

To

// dashboard.module.js

angular.module('dashboard', ['chart.js', 'interceptors']);

Other imperative JS:

// login_required.service.js

'use strict';

angular.
    module('interceptors').
        factory('LoginRequiredInterceptor', function($cookies, $location) {
            return function(response) {
                console.log('working')
                console.log('interceptor error')
                console.log(response)
                if (response.status == 401){
                    var currentPath = $location.path();
                    console.log(currentPath)
                    if (currentPath == '/') {
                        $location.path('/')
                    } else {
                        $location.path('/').search('next', currentPath)
                    }
                }
            }
        })

-

// interceptors.module.js

'use strict';

angular.module('interceptors', ['ngCookies']);

-

// dashboard.component.js

'use strict';

angular.module('dashboard').
    component('dashboard', {
        templateUrl: '/api/templates/dashboard.html',
        controller: function($cookies, $location, $stateParams, $rootScope, $scope) {
             // Nothing at this point
        }
    });

Really haven't updated the below from the project I cloned it from above:

// dashboard.service.js

'use strict';

angular.
    module('dashboard').
        factory('Dashboard', function(LoginRequiredInterceptor, $cookies, $httpParamSerializer, $location, $resource){

            var token = $cookies.get("token")
            if (token){
                commentCreate["headers"] = {"Authorization": "JWT " + token}
                commentDelete["headers"] = {"Authorization": "JWT " + token}
                commentUpdate["headers"] = {"Authorization": "JWT " + token}
            }

            return $resource(url, {}, {
                query: commentQuery,
                get: commentGet,
                create: commentCreate,
                delete: commentDelete,
                update: commentUpdate,
            })

        });

Lastly, the main config:

// app.config.js

'use strict';

angular.module('app').
    config(
        function(
            $locationProvider,
            $resourceProvider,
            $stateProvider,
            $urlRouterProvider,
            $authProvider
            ) {

            // Enable HTML5 mode
            $locationProvider.html5Mode({
                enabled:true
            })

            // Remove trailing slashes to avoid API issues
            $resourceProvider.defaults.stripTrailingSlashes = false;

            // Route handling if the URL does not match any of the below
            // it will send the user to the login screen
            $urlRouterProvider.otherwise('/');

            $stateProvider
                // The top URL (app/) is the login screen
                .state('/', {
                    url: '/',
                    views: {
                        'content@': {
                            component: 'login'
                        }
                    }
                })

                // Logout and reroute to the login screen
                .state('logout', {
                    redirectTo: '/'
                })

                // After successful login, the user is brought to the dashboard
                // Parent of the states below it
                .state('dashboard', {
                    url: '/dashboard',
                    views: {
                        'content@': {
                            component: 'dashboard'
                        }
                    },
                })

                // Test State1
                .state('dashboard.test1', {
                    views: {
                        'dashboard@dashboard': {
                            template: '<p style="position: absolute;top: 110%; left: 50%">Test1</p>'
                        }
                    }
                })

                // Test State2
                .state('dashboard.test2', {
                    views: {
                        'dashboard@dashboard': {
                            template: '<p style="position: absolute;top: 50%; left: 50%">Test2</p>'
                        }
                    }
                })
    });

Also, <scripts> I am reading in (at the bottom of my <body> tag):

<!-- base.html -->

<!-- Angular 1.x and Bootstrap UI libraries -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.min.js" integrity="sha256-zBy1l2WBAh2vPF8rnjFMUXujsfkKjya0Jy5j6yKj0+Q=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular-cookies.min.js" integrity="sha256-tVvnbUkwgprwLlmcKyx6/dz+KifqSSJ41vvUGvL72QM=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular-resource.min.js" integrity="sha256-J9EYt6krcoClMPGCdI0BA5vhMVHU/lu9vSnhbx0vfAI=" crossorigin="anonymous"></script>
<!--
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular-route.min.js" integrity="sha256-E6XubcgT4a601977ZZP4Yw/0UCB2/Ex+Bazst+JRw1U=" crossorigin="anonymous"></script>
-->

<!-- UI libraries -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/1.0.3/angular-ui-router.js" integrity="sha256-w3THDDhkzdjMczax74BBlkhjBxWIGisjArsP5wIQSHc=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.5.0/ui-bootstrap-tpls.min.js" integrity="sha256-tyfWW2LtJQNI+l3F0h6xDV/ij6Mfn8lwSKHWOsmEgXM=" crossorigin="anonymous"></script>

<!-- Misc 3rd Part Libraries -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/satellizer/0.14.1/satellizer.min.js" integrity="sha256-pcZRGEYkbl74zjS+YusQRvVWoFcwZTHLjmDCvbdX2ec=" crossorigin="anonymous"></script>

<!-- Chart related libraries -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js" integrity="sha256-SiHXR50l06UwJvHhFY4e5vzwq75vEHH+8fFNpkXePr0=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-chart.js/1.1.1/angular-chart.min.js" integrity="sha256-ydmVOl8gRR1E4yD1OC/aQdLNPCIKXSHIpl9yOu8EWek=" crossorigin="anonymous"></script>

<!-- Core application settings -->
<script src='{% static "js/app.module.js" %}' ></script>
<script src='{% static "js/app.config.js" %}' ></script>

<!-- Global application components -->
<script src='{% static "js/navbar/navbar.module.js" %}' ></script>
<script src='{% static "js/navbar/navbar.directive.js" %}' ></script>
<script src='{% static "js/sidebar/sidebar.module.js" %}' ></script>
<script src='{% static "js/sidebar/sidebar.directive.js" %}' ></script>

<!-- Page specific application componenets -->
<script src='{% static "js/login/login.module.js" %}' ></script>
<script src='{% static "js/login/login.component.js" %}' ></script>
<script src='{% static "js/dashboard/dashboard.module.js" %}' ></script>
<script src='{% static "js/dashboard/dashboard.component.js" %}' ></script>

Let me know if anything else would be helpful.

1条回答
在下西门庆
2楼-- · 2019-08-23 15:32

Well, I found a solution that seems to be working for me and is rather simple. There could be several issues with it, so feedback on why not to do this would be greatly appreciated.

I pretty much ditched the interceptors, services, etc.

Again, I really only have 2 URLs: '/' and '/dashboard'. The former is the login and the latter is where all the tools available to a user will be (eventually several dozen tools), but they will be child views of the parent dashboard. You can start to see this here:

// app.config.js

'use strict';

angular.module('app').
    config(
        function(
            $locationProvider,
            $resourceProvider,
            $stateProvider,
            $urlRouterProvider,
            $authProvider
            ) {

            // Enable HTML5 mode
            $locationProvider.html5Mode({
                enabled:true
            })

            // Remove trailing slashes to avoid API issues
            $resourceProvider.defaults.stripTrailingSlashes = false;

            // Route handling if the URL does not match any of the below
            // it will send the user to the login screen
            $urlRouterProvider.otherwise('/');

            $stateProvider
                // The top URL (app/) is the login screen
                .state('/', {
                    url: '/',
                    views: {
                        'content@': {
                            component: 'login'
                        }
                    }
                })

                // Logout and reroute to the login screen
                .state('logout', {
                    redirectTo: '/'
                })

                // After successful login, the user is brought to the dashboard
                // Parent of the states below it
                .state('dashboard', {
                    url: '/dashboard',
                    views: {
                        'content@': {
                            component: 'dashboard'
                        }
                    },
                })

                // Test child State1
                .state('dashboard.test1', {
                    views: {
                        'dashboard@dashboard': {
                            template: '<p style="position: absolute;top: 110%; left: 50%">Test1</p>'
                        }
                    }
                })

                // Test child State2
                .state('dashboard.test2', {
                    views: {
                        'dashboard@dashboard': {
                            template: '<p style="position: absolute;top: 50%; left: 50%">Test2</p>'
                        }
                    }
                })
    });

Here is the login where the JWT token is written to the cookie.

// login.component.js

'use strict';

angular.module('login').
    component('login', {
        templateUrl: 'api/templates/login.html',
        controller: function($cookies, $http, $location, $stateParams, $rootScope, $scope) {
            var loginUrl = 'api/users/login/'
            $scope.loginError = {}
            $scope.user = {}

            $scope.$watch(function() {
                if ($scope.user.password) {
                    $scope.loginError.password = ''
                } else if ($scope.user.username) {
                    $scope.loginError.username = ''
                }
            })

            var tokenExists = $cookies.get('token')
            if (tokenExists) {
                // verify token
                $scope.loggedIn = true;
                $cookies.remove('token')
                $scope.user = {
                    username: $cookies.get('username')
                }
                // window.location.reload()
            }

            // Main login handling for user
            $scope.doLogin = function(user) {
                // console.log(user)
                if (!user.username) {
                    $scope.loginError.username = ['This field may not be blank.']
                } 

                if (!user.password) {
                    $scope.loginError.password = ['This field is required.']
                }

                // If both the username and the password are supplied then POST it to the login API URL
                if (user.username && user.password) {
                    $http({
                        method: 'POST',
                        url: loginUrl, 
                        data: {
                            username: user.username,
                            password: user.password                            
                        },
                        headers: {}
                    }).then(function successCallback(r_data, r_status, r_headers, r_config) {
                        // console.log(r_data.data)
                        $cookies.put('token', r_data.data.token)
                        $cookies.put('username', r_data.data.username)
                        var token = $cookies.get('token')
                        // console.log(token)

                        $location.path('/dashboard')
                        // window.location.reload()                      
                    }, function errorCallback(e_data, e_status, e_headers, e_config) {
                        // Check if this is a 400 error which is related to an invalid password
                        if (e_data.status == 400) {
                            $scope.loginError.invalid = ['The credentials entered are invalid.']
                        }
                    })    
                } 
            }
        }
    })

Then for the dashboard I just did the following:

// dashboard.component.js

'use strict';

angular.module('dashboard').
    component('dashboard', {
        templateUrl: '/api/templates/dashboard.html',
        controller: function($cookies, $location, $stateParams, $rootScope, $scope) {
            var token = $cookies.get('token')
            console.log(token)
            if (token) {
                $location.path('/dashboard')
            } else {
                $location.path('/')
            }
        }
    });

It seems to work how I expect it to:

  • if you try to go /dashboard it will route you to the login screen
  • if you login and are routed to /dashboard you can type in /dashboard to the URL and it displays it
  • if you logout, it will not allow you to view /dashboard by typing it in or hitting the back button in browser
  • it doesn't allow access to the subviews directly, which I think is just due to routing: that subviews can't be rendered if the parent view cannot.

Anyway, feedback would be greatly appreciated.

EDIT: Realizing how similar this is to the project I am copying, but instead of an interceptor I have it in in the dashboard component.

查看更多
登录 后发表回答