运用service完成登录、权限掌握

文章泉源:http://blog.ddlisting.com

官网关于登录、用户权限的引见只需一段简朴的申明,并没有细致申明怎样运用service完成权限掌握。下面地点是官网的说法:

https://guides.emberjs.com/v2.6.0/applications/services/

An Ember.Service is a long-lived Ember object that can be made available in different parts of your application.
Services are useful for features that require shared state or persistent connections. Example uses of services might include:

  1. User/session authentication.

  2. Geolocation.

  3. WebSockets.

  4. Server-sent events or notifications.

  5. Server-backed API calls that may not fit Ember Data.

  6. Third-party APIs.

  7. Logging.

service是啥东西呢?简朴讲service也是一个Ember.Object只不过这个对象与一般的对象有点不一样。起首这类对象是放在文件夹appName/app/services目录下。其次放在这个目录下的对象Ember会自动注册(registered)或许注入(injection)到Ember项目中。这类对象有以下2个特征

  1. 对象声明周期是session级别的

  2. 在Ember项目标任何地方都能够挪用

恰是基于这两个特征才完成权限的掌握。最简朴的例子就是用户的登录题目。现在也有现成的插件完成权限的掌握,请看运用ember-simple-auth完成Ember.js运用的权限掌握所形貌的要领,然则假如要根据本身项目须要去完成权限掌握那末又怎样做呢?

本篇博文将为你引见怎样运用service完成权限掌握,我会建立一个简朴的登录示例加以申明。若有不妥迎接留言斧正。

构建项目

ember new secretcodez
cd secretcodez
ember s

考证项目是不是建立胜利http://localhost:4200。看到Welcome to Ember申明项建立胜利。下面建立演示所需文件。

建立文件

ember g route secret
ember g route login
ember g route application

ember g component secret-page
ember g component login-page

ember g model code description:string

ember g adapter application

项目演示用到的文件基础就这些。

secret页面

{{! app/templates/secret.hbs }}
{{secret-page model=model}}
{{! app/tempalates/components/secret-page.hbs}}
<h1>secret page</h1>

<ul>
    {{#each model as |code|}}
    <li>
        <strong>{{code.description}}</strong>
    </li>
    {{/each}}
</ul>

后端效劳

为了测试建立一个简朴的后端效劳顺序,运用的是Node,然后写死一些测试数据。就没必要动牛刀,建立一个数据库了!

ember g server
npm install
npm install body-parser --save-dev

实行完ember g server后,在APP目录下建立一个nodejs顺序,自动植入到当前项目中,接见的domain和port与ember接见域名端口一致。

翻开index.js编辑后端要求监听。

// server/index.js

const bodyParser = require('body-parser');

module.exports = function(app) {

  app.use(bodyParser.urlencoded({ extended: true }));

  app.get('/api/codes', function (req, res) {    
    return res.status(200).send({
          codes: [
              { id:1, description: '为了测试建立一个简朴的后端效劳顺序,运用的是Node,然后写死一些测试数据。就没必要动牛刀,建立一个数据库了!' },
              { id:2, description: '本篇博文将为你引见怎样运用service完成权限掌握,我会建立一个简朴的登录示例加以申明。若有不妥迎接留言斧正。' }
          ]
      });
  });

};

既然用到本身的后端效劳那末对应的你就须要自定义适配器了。简朴起见就建立RESTAdapter适配器吧。JSONAPIAdapter适配器相对贫苦点,须要花样化数据为json api

// app/adapters/application.js

export default DS.RESTAdapter.extend({
  namespace: 'api'
});

运用属性namespace指定URL前缀,比方要求URL为http://localhost:4200/api/codes,自动在要求上到场前缀api

修正路由,猎取后端数据。

// app/routes/secret.js

export default Ember.Route.extend({
  model() {
    // 返回后端数据,这些数据直接从 server/index.js 猎取
    return this.store.findAll('code');
  }
});

从新启动项目。搜检项目是不是有毛病!假如启动没题目,那末接见http://localhost:4200/secret你也会获得以下截图的结果。

《运用service完成登录、权限掌握》

从截图中能够看到发送一个要求http://localhost:4200/api/codes,而且从这个要求中猎取到效劳端返回的数据。你能够直接把这个URL放到浏览器地点栏实行,能够清晰的看到返回的数据。数据的花样是一般的json花样。

现在的结果是任何人都能够接见,还没完成权限掌握的结果。那末怎样去完成呢?不知道你是不是看过前面的文章adapter与serializer运用示例,假如你看过内里有引见过在要求头加考证信息这个小结。假如我也想这么完成掌握接见API的权限怎样做呢?

修正效劳端,到场权限校验

// 阻拦 /api/codes 要求
app.get('/api/codes', function(req, res) {
    //猎取数据之前先校验要求者是不是有权接见资本
    //  做一个异常简朴的推断,假如要求的头信息不等于BLOG.DDLISTING.COM则以为无权限
    if (req.headers['authorization'] !== 'BLOG.DDLISTING.COM') {
        return res.status(403).send('您无权接见此资本!')
    }
    // 直接返回准确状况和测试数据
    return res.status(200).send({
        codes: [
            { id:1, description: '为了测试建立一个简朴的后端效劳顺序,运用的是Node,然后写死一些测试数据。就没必要动牛刀,建立一个数据库了!' },
            { id:2, description: '本篇博文将为你引见怎样运用service完成权限掌握,我会建立一个简朴的登录示例加以申明。若有不妥迎接留言斧正。' }
        ]
    });
})

注重:_代码只列出重要部份,其他的稳定。_
在代码中到场了简朴的权限校验,一般authorization的值应该是变化的或许是每一个用户都是唯一的,比方oauth2中的access token。当你再次接见之前的资本http://localhost:4200/secret能够看到,报错了,提醒无权接见。以下截图:

《运用service完成登录、权限掌握》

明显如许的校验是没啥意义的,那末假如你也想模仿Oauth2也天生一个唯一的access token,你能够要求之前起首猎取一个access token。然则这个access token不是随意就可以猎取的,须要经由过程登录胜利后才猎取到。下面到场模仿登录的顺序。仍然是修正server/index.js

// 登录
app.post('/api/login', function(req, res) {
    //推断用户名和暗码是不是准确,这里就直接推断字符串了,现实中一般是经由过程查询数据去推断登录的用户是不是存在
    if (req.body.username === 'blog.ddlisting.com'
      && req.body.password === 'yes') {
          res.send({ access_token: 'BLOG.DDLISTING.COM' });
      } else {
          res.status(400).send({ error: '猎取token毛病!' });
      }
});

有了后端的效劳以后明显我们须要在前端增添一个登录的表单,供应用户登录而且登录胜利以后还要把猎取到的access_token保留好,在发送要求的时刻设置到要求的头。这个时刻就须要用到service了!!

登录

登录表单

{{! app/templates/login.hbs 登录}}
{{login-page}}
{{! app/templates/components/login-page.hbs 登录表单}}

{{link-to '点击检察有权才接见的资本' ’secret}}

<h2>登录</h2>
<p>
    默许的用户名和暗码为:blog.ddlisting.com/yes
</p>

<form class="" method="post" {{action 'authenticate' on='submit'}}>
    {{input type="text" value=username placeholder='blog.ddlisting.com'}}
    {{input type="password" value=password placeholder="暗码"}}
    <br>
    <button type="submit">登录</button>
</form>

登录处置惩罚

在组件类中增加处置惩罚登录的action。

// app/components/login-page.js

import Ember from 'ember';

export default Ember.Component.extend({
    authManager: Ember.inject.service(),  //注入servi'auth-manager'ce
    actions: {
        authenticate() {
            const { username, password } = this.getProperties('username', 'password');
            //挪用service类中的authenticate要领校验登录的用户
            this.get('authManager').authenticate(username, password),then(() => {
                console.log('登录胜利');
            }, (err) => {
                console.log('登录失利');
            });
        }
    }
});

在这个类中运用了service类,而且挪用此类中的authenticate要领。代码中的属性authManager就是一个service实例。下面定义service类。

ember g service auth-manager
// app/serivces/auth-manager.js

import Ember from 'ember';

export default Ember.Service.extend({
    accessToken: null,

    // 推断accessToken是不是是空
    isAuthenticated: Ember.computed.bool('accessToken'),

    // 提议要求校验登录用户
    authenticate(username, password) {
        return Ember.$.ajax({
            method: 'post',
            url: '/api/login',
            data: { username: username, password: password }
        }).then((res) => {
            // 设置返回的access_token到service类的属性中
            this.set('accessToken', res.access_token);
        }, (err) => {
            //登录失利
        });
    },
    invalidate() {
        this.set('accessToken', null);
    }
});

在组件类login-page.js中并没有直接发要求校验用户是不是登录胜利,而是经由过程挪用serivce类的要领去校验,目标是为了把返回的值保留到service的属性中,这也是利用它的特征。要领invalidate的目标是实行退出登录操纵,把保留到service属性中的值置空,使得盘算属性isAuthenticated返回false

一切都定义好了下面就是怎样运用这个service属性了!修正适配器的代码,在要求头中到场accessToken

// import JSONAPIAdapter from 'ember-data/adapters/json-api';
import DS from 'ember-data';

// 不运用默许适配器JSONAPIAdapter,而是运用RESTAdapter
export default DS.RESTAdapter.extend({
    namespace: 'api',  //接见要求前缀: http://localhost:4200/api/codes
    // 到场要求头
    authManager: Ember.inject.service('auth-manager'),
    headers: Ember.computed('authManager.accessToken', function() {
        //动态返回accessToken的值
        return {
            'authorization': `${this.get('authManager.accessToken')}`
        };
    })
});

到此代码基础写完了,为了处置惩罚效劳端返回的毛病直接在application路由中阻拦error事宜,在这个事宜中处置惩罚毛病的状况。
申明:一切的子路由的error事宜都邑自动冒泡到路由applicationerror事宜中。

// app/routes/application.js
import Ember from 'ember';

export default Ember.Route.extend({
    actions: {
        // 处置惩罚一切的error事宜
        error(reason, transition) {
            //假如涌现毛病直接转到登录界面
            this.transitionTo('login');
            return false;
        }
    }
});

项目重启终了(是手动停止在启动,不然会涌现service未定义的状况)以后能够看到界面直接跳转到了登录页面,完成了简朴的权限阻拦(无权先登录)。

《运用service完成登录、权限掌握》

未登录直接点击链接“点击检察有权才接见的资本”结果

《运用service完成登录、权限掌握》

能够看到浏览器掌握台打印信息显现资本无权接见,返回的代码是403

输入毛病的用户名或暗码的状况:

《运用service完成登录、权限掌握》

登录胜利再接见受权资本

《运用service完成登录、权限掌握》

登录胜利以后再点击链接能够一般接见了,而且准确看到后端返回的数据。

纵然你点击链接“点击检察有权才接见的资本”也照样会跳转回登录页面。那末最先测试登录后的结果,在表单中输入准确的用户名和暗码。点击登录后跳转到了

退出

有登录就会有退出,退出相对简朴,只需销毁了service类中的属性accessToken值即可。

{{! app/tempalates/components/secret-page.hbs}}
<h1>secret page</h1>

<ul>
    {{#each model as |code|}}
    <li>
        <strong>{{code.description}}</strong>
    </li>
    {{/each}}
</ul>


<br><br>

<button type="button" {{action 'invalidate'}}>退出</button>
// app/components/secret-page.js
import Ember from 'ember';

export default Ember.Component.extend({
    //注入service
    authManager: Ember.inject.service('auth-manager'),

    actions: {
        invalidate() {
            this.get('authManager').invalidate();  //退出登录状况
            //临时粗犷处置惩罚,直接强迫革新,从新进入application路由触发error事宜,再次推断是不是登录
            location.reload();
        }
    }
});

关于退出事宜的处置惩罚就比较简朴粗犷了,直接革新页面,因为属性authManager的值已设置为null所以提议要求的时刻是无权限的会再次触发error事宜,然后跳转到登录页面。

到这里,基础上完成了一个简朴的权限掌握功用。例子比较简朴,然则处置惩罚的思绪大体上是如许做的,能完成如许的功用是基于service类的特征。也愿望读者能经由过程本例明白晓得怎样运用service

项目代码:https://github.com/ubuntuvim/secretcodez,有疑问迎接给我留言。
您的支撑是我继承写作的最大动力,感谢!!

    原文作者:ember_teach
    原文地址: https://segmentfault.com/a/1190000005720340
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞