使用AngularJS完成登录表单示例

使用AngularJS完成登录表单示例,angularjs,login,angular-ui,Angularjs,Login,Angular Ui,在上周,我创建了一个完整的示例web应用程序,以演示使用AngularJS的自定义登录表单实现。这对我来说并不太容易,因为我是一名Java开发人员,而且我在JavaScript方面没有太多经验。但最终我的代码运行良好。万岁:-) 我想和你们分享我的解决方案,如果你们能看一看并给我任何简化的建议,我会很高兴的。请随意批评我的JavaScript代码 在我的演示应用程序中,服务器端资源(图像、html页面和RESTFul api)受OpenAM保护 为了避免OpenAm中受保护URL的错误和复杂配置

在上周,我创建了一个完整的示例web应用程序,以演示使用AngularJS的自定义登录表单实现。这对我来说并不太容易,因为我是一名Java开发人员,而且我在JavaScript方面没有太多经验。但最终我的代码运行良好。万岁:-)

我想和你们分享我的解决方案,如果你们能看一看并给我任何简化的建议,我会很高兴的。请随意批评我的JavaScript代码

在我的演示应用程序中,服务器端资源(图像、html页面和RESTFul api)受OpenAM保护

为了避免OpenAm中受保护URL的错误和复杂配置,我在web应用程序中创建了两个文件夹,一个用于公共内容,另一个用于受保护内容

我的war文件(web应用程序)的结构如下所示:

web-ui.war
|-app
|  |-components
|     |-protected <-- protected web folder by OpenAM
|     |  |-welcome
|     |     |-welcome.html
|     |-public
|     |  |-help
|     |  |  |-help-general.html
|     |  |  |-help-howItWorks.html
|     |  |-home
|     |  |  |-home.html
|     |  |-log-in
|     |  |  |-logIn.html
|     |  |  |-logIn-controller.js
|     |  |  |-logIn-factory.js
|     |  |-sign-up
|     |  |  sign-up.html
|     |  |-app-directive.js
|     |  |-app-module.js
|     |  |-app-route.js
|- assets
|   |-css
|   |  |-app.css
|   |-img
|   |-libs
|   |  |-angular
|   |  |  |-1.4.7
|   |  |     |...
|   |  |-angular-ui
|   |  |  |-0.2.15
|   |  |     |...
|   |  |-bootstrap
|   |  |  |-3.3.5
|   |  |     |...
|   |  |-ui-bootstrap
|   |  |  |-0.14.2
|   |  |     |...
|-WEB-INF
|-index.html
我创建了两个指令来处理文本框内的onEnter事件,并将焦点设置在文本元素上(显示闪烁的光标)

app-directive.js文件:

var app = angular.module("myApp", ['ui.bootstrap', 'ui.router']);
app.directive('myEnter', function () {
    return function (scope, element, attrs) {
        element.bind("keydown keypress", function (event) {
            if(event.which === 13) {
                scope.$apply(function (){
                    scope.$eval(attrs.myEnter);
                });

                event.preventDefault();
            }
        });
    };
});

app.directive('autoFocus', function($timeout) {
    return {
        restrict: 'AC',
        link: function(_scope, _element) {
            $timeout(function(){
                _element[0].focus();
            }, 0);
        }
    };
});
app-routes.js文件的重要部分是“数据:{requiresLogin:true}”。这一行告诉客户端的页面路由逻辑,用户希望访问受保护的内容。如果用户未登录,则需要显示登录页面,并且在成功登录过程后,需要显示原始请求页面

这个js文件中的另一个重要行与“$stateChangeStart”事件有关。它在url每次更改时激发(模板html路由开始工作)。在这种情况下,请求的url存储在loginFactory中,以防需要显示登录页面。登录过程后,需要显示原始请求页面,因此我们需要此信息以供进一步使用

app-routes.js文件:

app.config(function($stateProvider, $urlRouterProvider) {
    $urlRouterProvider.otherwise('/home');

    $stateProvider
        // public pages
        .state('home', {
            url: '/home',
            templateUrl: 'app/components/public/home/home.html'
        })
        .state('log-in', {
            url: '/log-in',
            templateUrl: 'app/components/public/log-in/logIn.html'
        })
        .state('sign-up', {
            url: '/sign-up',
            templateUrl: 'app/components/public/sign-up/signUp.html'//,
        })
        .state('help-general', {
            url: '/help-general',
            templateUrl: 'app/components/public/help/help-general.html'
        })
        .state('help-howItWorks', {
            url: '/help-howItWorks',
            templateUrl: 'app/components/public/help/help-howItWorks.html'
        })

        // private pages
        .state('private/welcome', {
            url: '/private/welcome',
            templateUrl: 'app/components/protected/welcome/welcome.html',
            data : { requiresLogin: true }
        });
});

app.run(function($rootScope, $state, loginFactory) {
    $rootScope.$on('$stateChangeStart', function(event, toState) {
        var isAuthenticationRequired = toState.data && toState.data.requiresLogin && !loginFactory.isLoggedIn();

        if (isAuthenticationRequired == true) {
            loginFactory.setToState(toState);
            event.preventDefault();
            $state.go('log-in');
        }
    });
 });
在my login.html文件中,自动聚焦指令用于用户名文本框,输入指令用于密码按钮。如果用户在输入密码后按enter键,则调用控制器中的login()方法。当用户单击登录按钮时,也会应用相同的行为

在显示login.html之前,我们调用控制器的reset()方法。它清除上一个密码文本框的值并隐藏“无效用户名或密码”标签

不含任何设计元素的login.html文件:

<div class="..." ng-controller="loginController" data-ng-init="reset()">
    <h3>Login or <a ui-sref="user-registration">Sign up</a></h3>

<div class="...">
    <div class="col-xs-12 col-sm-6">
        <input type="text" class="..." placeholder="email address" ng-model="user.username" auto-focus>
        <input type="password" class="..." placeholder="Password" ng-model="user.password" my-enter="login()">

        <span class="..." ng-if="!firstAttempt">Invalid username or password</span>
        <span class="..." ng-if="firstAttempt"></span>

        <button class="..." ng-click="login()">Login</button>
    </div>
</div>
login-controller.js文件:

app.controller('loginController', function($scope, loginFactory, $location) {
    $scope.loggedIn = false;
    $scope.user = {};
    $scope.firstAttempt = true;

    $scope.login = function() {
        loginFactory.callAuthService($location, $scope);
        $scope.firstAttempt = false;
    };

    $scope.reset = function() {
        $scope.firstAttempt = true;
        $scope.user.password = '';
    }
});
就这样

我有一些问题:

  • 从/app/components/protected区域延迟加载js文件:I 希望将与模板相关的js文件(例如:控制器)保存在 与html文件相同的目录,并使用 模板包含html文件。是否有任何现有的最佳实践

  • 我的auth servlet将带有令牌的cookie发送回浏览器和 创建新url时,浏览器将令牌cookie发送回服务器 请求。如果cookie中的令牌是正确的,那么OpenAM将给出 访问受保护的资源。我听说饼干不安全 存储令牌信息的方法。我想用HTML5来代替 功能:将其存储在浏览器的区域设置存储中并发送 每次请求都会自动发送到服务器。你能帮我实现这个吗

  • 这个问题与指令有关:如果我将“myEnter”指令重命名为“oneter”或“customEnter”o“caEnter”,那么它将不再工作。 为什么?我只能在指令名称前使用'my'prefx吗

  • 我试图遵循AngularJS的命名约定 相关的JavaScript文件,现在我有很多。的确如此 将它们全部包含到index.html文件中会让人不舒服 我认为这对web应用程序的性能不好。是 有没有最佳做法来合并/合并“数百万”分离的资产 在应用程序进入生产服务器之前,是否将JavaScript文件合并为一个


  • 读起来太长了。你能不能只添加相关的内容和代码。Plunkr会很好。是的,这不是一篇短文,因为它是一个完整的例子。我之所以发布它,是因为我想知道你对它的看法。这应该发布在codereview.stackexchange.com上。这是离题的。我投票以离题的方式结束这个问题,因为它要求进行代码审查,因此应该发布在codereview.stackexchange.com上。我还有一些问题。
    app.factory('loginFactory', function($http) {
        var loggedIn = false;
        var toState;
    
        return {
            isLoggedIn: function() {
                return loggedIn;
            },
    
            setToState: function(state) {
                toState = state;
            },
    
            callAuthService: function($location, $scope) {
                var formData = 'username=' + $scope.user.username + '&password=' + $scope.user.password;
                var response = $http({
                    method: 'POST',
                    url: 'http://...:8080/loginservlet/public/auth',
                    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
                    data: formData})
    
                .success(function (data, status, headers, config) {
                    loggedIn = true;
    
                    if (toState) {
                        $location.path(toState.url);
                        toState = undefined;
                    } else
                        $location.path('private/welcome');
                })
    
                .error(function (data, status, headers, config) {
                    loggedIn = false;
                });
            }
        };
    });
    
    app.controller('loginController', function($scope, loginFactory, $location) {
        $scope.loggedIn = false;
        $scope.user = {};
        $scope.firstAttempt = true;
    
        $scope.login = function() {
            loginFactory.callAuthService($location, $scope);
            $scope.firstAttempt = false;
        };
    
        $scope.reset = function() {
            $scope.firstAttempt = true;
            $scope.user.password = '';
        }
    });