不少网站都有登陆功能,对于Ember的应用咱们怎么实现权限的控制呢?本篇将为你演示一个最经常使用的权限控制例子:用户登陆。javascript
要实现登陆最经常使用的方式是经过判断session值,若是session中存在你所须要的值则能够认为是用户是通过了登陆而且把用户信息设置到session了,若是session中没有用户信息则认为用户没有登陆,直接跳转到登陆或者注册页面。html
本篇会引入一个专门用于控制权限的插件ember-simple-auth,文章中大部分代码是直接参考这个插件的文档所写。若是你须要项目的代码请移步github下载。java
好了,废话少说,直接放码出来吧。node
本文会使用Ember CLI名称建立项目和项目所需的文件,更多有关Ember CLI的命令请自行到官网学习。git
ember new chapter8_simple_auth cd chapter8_simple_auth ember server
若是你的项目搭建成功执行http://localhost:4200,会看到Welcome to Ember,说明项目搭建成功。github
本项目会升级Ember版本,目前(_2015-11-18_)来讲若是是使用Ember CLI命令安装的项目Ember的版本是1.13.7。升级后使用的版本是2.0.0-beta.3。web
升级步骤:ajax
修改bower.json
修改后此文件主要的代码以下:shell
{ "dependencies": { "ember": "2.0.0-beta.3" }, "resolutions": { "ember": "2.0.0-beta.3" } }
删除原有的Ember
必需要手动删除原有的版本,不然由于缓存的问题使用命令从新安装的时候可能安装不成功。手动删除以下目录:appName/bower_components/ember
npm
安装新版本Ember
使用命令:bower install
,从新安装Ember。
检查是否安装成功。
打开appName/bower_components/ember/ember.js
,能够看到Ember
是那个版本。若是是2.0.0-beta.3说明升级成功。
一样的方式升级Jquery
若是你升级不成功,你能够参考个人项目的bower.json、package.json升级。修改这两个文件后执行命令bower install
升级。
重启项目
能够看到浏览器控制台打印出Ember的版本信息。
2015-11-18 23:54:08.902 ember.debug.js:5202 DEBUG: ------------------------------- 2015-11-18 23:54:08.916 ember.debug.js:5202 DEBUG: Ember : 2.0.0-beta.3 2015-11-18 23:54:08.916 ember.debug.js:5202 DEBUG: jQuery : 2.1.4 2015-11-18 23:54:08.917 ember.debug.js:5202 DEBUG: -------------------------------
到此项目的升级工做完成。
直接使用npm命令安装,安装的方法能够参考官方教程,直接在项目目录下运行ember install ember-simple-auth
便可完成安装。能够在appName/bower_components
看到安装的插件。
{{! app/templates/application.hbs }} <h2 id="title">This is my first auth proj</h2> {{#if session.isAuthenticated}} <p> <a {{action 'invalidateSession'}} style="cursor: pointer;">Logout</a> </p> {{else}} <p> <a {{action 'sessionRequiresAuthentication'}} style="cursor: pointer;">Login</a> </p> {{/if}} {{outlet}}
session.isAuthenticated
是插件ember-simple-auth封装好的属性,若是没有登陆isAuthenticated为false,sessionRequiresAuthentication
也是插件ember-simple-auth提供的方法。此方法会自动根据用户实现的authenticate
方法校验用户是否已经登陆(isAuthenticated
为true
)。
使用Ember CLI建立两个组件:login-form
和get-quotes
。
ember g component login-form ember g component get-quotes
分别编写这两个组件和组件对应的模板文件。
login-form.js
// app/components/login-form.js import Ember from 'ember'; export default Ember.Component.extend({ // authenticator: 'authenticator: custom', actions: { authenticate: function() { var user = this.getProperties('identification', 'password'); this.get('session').authenticate('authenticator:custom', user).catch((msg) => { this.set('errorMessage', msg); }); } } });
其中authenticator
属性执行了一个自定义的身份验证器custom
。identification
和password
是页面输入的用户名和密码。
getProperties
方法会自动获取属性值并自动组装成hash形式({key: value}
形式)。msg
是方法authenticate
验证不经过的提示信息。
在此简单处理,直接放回到界面显示。
login-form.hbs
{{! app/templates/login-form.hbs }} <form {{action 'authenticate' on='submit'}}> <div class="form-group"> <label for="identification">Login</label> {{input value=identification placeholder="enter your name" class="form-control"}} </div> <div class="form-group"> <label for="password">Login</label> {{input value=password placeholder="enter password" class="form-control" type="password"}} </div> <button type="submit" class="btn btn-default">Login</button> </form> {{#if errorMessage}} <div class="alert alert-danger"> <strong>Login failed: </strong>{{errorMessage}} </div> {{/if}}
这个文件比较简单没什么好说,errorMessage
就是组件类中返回的提示信息。
get-quotes.js
// app/components/get-quotes.js import Ember from 'ember'; export default Ember.Component.extend({ gotQuote: false, quote: "", actions: { getQuote: function() { var that = this; // 返回一个随机的字符串 Ember.$.ajax({ type: 'GET', // url: 'http://localhost:3001/api/protected/random-quote', url: 'http://localhost:3001/api/random-quote', success: function(response) { that.setProperties({ quote: response, gotQuote: true }); }, error: function(error) { alert("An error occurred while processing the response."); console.log(error); } }); } } });
此组件模拟登录以后才能访问的资源,经过Ajax获取一个随机的字符串。
请求的服务代码你也能够从github上下载,下载以后按照文档安装,直接运行node server.js
既可,服务器端是一个nodejs程序,若是你的电脑没有安装nodejs,请自行下载安装。
这两个页面比较简单,直接调用组件。为何我没有直接把组件代码放在这两个页面呢??咱们知道Ember2.0以后官方不推荐使用控制器,控制器的做用在弱化,组件变得愈来愈重要。
既然咱们项目使用的是Ember2.0版本那就必需要用组件去替代控制器实现某些逻辑的判断。
{{! app/templates/login.hbs }} {{login-form}}
{{! app/templates/protected.hbs }} {{get-quotes}}
咱们直接把登录使用的用户名和密码提示出来,为了测试方便嘛,再者项目尚未注册功能。
{{! app/templates/index.hbs }} {{#unless session.isAuthenticated}} <div class="alert alert-info"> You can {{#link-to 'login' className="alert-link"}}log in {{/link-to}} with login <code>ember</code> and password <code>123</code>. </div> {{/unless}}
可是用户名和密码为何是ember
和123
呢??你看到服务器代码里的user-routes.js就明白了,github上用的是gonto
,我下载以后作了点小修改。你能够修改为你喜欢的字符串。
到此常规的文件就建立完成了,下面的内容才是重头戏。到目前为止咱们还没使用过任何有关插件ember-simple-auth
的内容。
ember g route login ember g route protected ember g route application
执行命令的时候要注意别把以前的模板覆盖了!!!下面是这几个文件的内容。
application.js
// app/routes/application.js import Ember from 'ember'; import ApplicationRouteMixin from 'simple-auth/mixins/application-route-mixin'; export default Ember.Route.extend(ApplicationRouteMixin, { actions: { invalidateSession: function() { this.get('session').invalidate(); } } });
这个类首先混合了ApplicationRouteMixin
类的特性,而后再加上自定义的特性。注意第二行代码,引入了插件ember-simple-auth
的类ApplicationRouteMixin
。更多有关这个类的介绍请点击连接查看。session
是插件内置的属性。方法invalidate
设置session
为无效或者说是当前认证无效,更多详细信息请看方法的API介绍。
protected.js
// app/routes/protected.js import Ember from 'ember'; import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin'; // 实现AuthenticatedRouteMixin的类会自动根据权限过滤,若是通过登陆页面直接进入这个route会自动跳转到登陆页面 export default Ember.Route.extend(AuthenticatedRouteMixin, { });
此类也是引入插件ember-simple-auth
封装好的类AuthenticatedRouteMixin
。混合了此类的类会自动根据权限过滤,若是没有经过认证而直接访问这个route会被强制跳转到登陆页面。
login.js
// app/routes/login.js import Ember from 'ember'; export default Ember.Route.extend({ // 清空提示信息 setupController: function(controller, model) { console.log("route:login model = " + model); controller.set('errorMessage', null); } });
这个route的做用是清空页面的提示信息,若是不清空你再次进入的时候仍是会看到提示信息。
路由protected之因此能实现无权限重定向到登陆页面是由于在controller:login中指定了登陆处理类。
login.js
// app/controllers/login.js import Ember from 'ember'; import LoginControllerMixin from 'simple-auth/mixins/login-controller-mixin'; export default Ember.Controller.extend(LoginControllerMixin, { });
此类引入插件封装好的登陆处理类LoginControllerMixin
,遗憾的是在插件目录下并无发现这个类,看不到里面的实现!
最后的这两个类是整个项目最核心的东西——自定义校验器、受权者。
受权者类 authorizer/custom.js
// app/authenrizers/custom.js import Ember from 'ember'; import Base from 'simple-auth/authorizers/base'; export default Base.extend({ authorize: function(jqXHR, requestOptions) { var accessToken = this.get('session.content.secure.token'); if (this.get('session.isAuthenticated') && !Ember.isEmpty(accessToken)) { // setRequestHeader方法自定义请求头信息:键为Authorization,值为Ember+accessToken // 有关这个方法的介绍请看[API介绍](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader) jqXHR.setRequestHeader('Authorization', 'Ember' + accessToken); } } });
直接继承Base
类,从新实现authorize
方法。或者你亦能够像github上的教程使用插件已经定义好的类。authorize
方法第一个参数是须要设置的session
数据,第二个参数是一个回调函数,更多详情状况接口API。
验证器类 authenticators/custom.js
// app/authenticators/custom.js import Ember from 'ember'; import Base from 'simple-auth/authenticators/base'; export default Base.extend({ tokenEndpoint: 'http://localhost:3001/sessions/create', restore: function(data) { return new Ember.RSVP.Promise(function(resolve, reject) { if (!Ember.isEmpty(data.token)) { resolve(data); } else { reject(); } }); }, authenticate: function(options) { return new Ember.RSVP.Promise((resolve, reject) => { Ember.$.ajax({ url: this.tokenEndpoint, type: 'POST', data: JSON.stringify({ username: options.identification, password: options.password }), contentType: 'application/json;charset=utf-8', dataType: 'json' }).then(function(response) { Ember.run(function() { resolve({ token: response.id_token }); }); }, function(xhr, status, error) { var response = xhr.responseText; Ember.run(function() { reject(response); }); }); }); }, invalidate: function() { console.log('invalidate...'); return Ember.RSVP.resolve(); } });
这个类代码比较多,也比较复杂。目前官方提供了三种经常使用的验证器。
可是本项目使用的自定义的验证器。须要注意的是自定义的验证器须要实现restore
、authenticate
、invalidate
这个三个方法,最后一个方法不强制要求重写,可是前面两个方法必须重写。从代码实现能够看到这几个方法都返回了Promise对象。
代码首先是执行了Ajax请求http://localhost:3001/sessions/create
,若是执行成功则返回token
,不然返回出错信息,返回的错误信息能够在user-routes.js上看到,下载代码后你能够修改为本身喜欢的提示信息。
到此项目的主要代码都已实现了,下面为了项目能正常运行还须要修改项目的配置文件config/environment.js
。
/* jshint node: true */ module.exports = function(environment) { var ENV = { // ……与原文件同样 APP: { // Here you can pass flags/options to your application instance // when it is created }, contentSecurityPolicy: { 'default-src': "'none'", 'script-src': "'self'", 'font-src': "'self' *", 'connect-src': "'self' *", // Allow data (ajax/websocket) from http://localhost:3001 'img-src': "'self'", 'style-src': "'self' 'unsafe-inline' *", // Allow inline styles 'media-src': "'self'" } }; ENV['simple-auth'] = { store: 'simple-auth-session-store:local-storage', authorizer: 'authorizer:custom', crossOriginWhitelist: ['http://localhost:3001/'], // Ajax跨域设置 // routeAfterAuthentication: '/', //登陆成功后跳转到的页面 authenticationRoute: 'login' // 登陆不成功转回登陆页面 }; // ……与原文件同样 return ENV; };
没有列出的代码与默认生成的代码是一致的。
最后重启项目测试效果。
首先咱们直接访问 http://localhost:4200/protected
,能够看到直接被重定向到http://localhost:4200/login
(前提是你还没登录过)。而后再访问 http://localhost:4200
进入到项目首页。能够看到提示登录的用户名和密码。而后点击login
转到登录界面。
下面是演示效果
没有输入用户、密码
若是没有输入用户名或者密码其中之一,或者都不输入就点击login,会出现如图提示信息。你也能够看浏览器控制台打印的日志信息,能够看到返回的状态码为400,这个状态码也是在user-routes.js中设置的。
用户名和密码不匹配
登录成功的状况
能够看到浏览器URL转到http://localhost:4200/protected
。而后点击按钮"Get Random quote",能够看到返回随机的字符串。
每点击一次就发送一次请求http://localhost:3001/api/random-quote
,请求返回一个随机的字符串。
到此,使用插件ember-simple-auth
实现ember应用的权限控制的内容所有结束完毕,各位读者们不知道大家是否看得明白,若是以为文章将不对的地方欢迎给我留言,若是你以为做者大半夜写文章精神可嘉也欢迎给我点个赞吧 =_=!!
若是发现链接没法访问,那么你可能须要fanqiang