资讯专栏INFORMATION COLUMN

使用service实现登录、权限控制

Aomine / 1137人阅读

摘要:就没必要动牛刀,创建一个数据库了执行完后,在目录下创建一个程序,自动植入到当前项目中,访问的和与访问域名端口一致。就没必要动牛刀,创建一个数据库了本篇博文将为你介绍如何使用实现权限控制,我会创建一个简单的登录示例加以说明。

文章来源: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:

User/session authentication.

Geolocation.

WebSockets.

Server-sent events or notifications.

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

Third-party APIs.

Logging.

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

对象声明周期是session级别的

在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}}

secret page

    {{#each model as |code|}}
  • {{code.description}}
  • {{/each}}
后端服务

为了测试创建一个简单的后端服务程序,使用的是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你也会得到如下截图的效果。

从截图中可以看到发送一个请求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可以看到,报错了,提示无权访问。如下截图:

显然这样的校验是没啥意义的,那么如果你也想模拟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}}

登录

默认的用户名和密码为:blog.ddlisting.com/yes

{{input type="text" value=username placeholder="blog.ddlisting.com"}} {{input type="password" value=password placeholder="密码"}}
登录处理

在组件类中添加处理登录的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未定义的情况)之后可以看到界面直接跳转到了登录页面,实现了简单的权限拦截(无权先登录)。

未登录直接点击链接“点击查看有权才能访问的资源”效果

可以看到浏览器控制台打印信息显示资源无权访问,返回的代码是403

输入错误的用户名或密码的情况:

登录成功再访问授权资源

登录成功之后再点击链接可以正常访问了,并且正确看到后端返回的数据。

即使你点击链接“点击查看有权才能访问的资源”也还是会跳转回登录页面。那么开始测试登录后的效果,在表单中输入正确的用户名和密码。点击登录后跳转到了

退出

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

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

secret page

    {{#each model as |code|}}
  • {{code.description}}
  • {{/each}}


// 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,有疑问欢迎给我留言。
您的支持是我继续写作的最大动力,谢谢!!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79664.html

相关文章

  • 手摸手,带你用vue撸后台 系列二(登录权限篇)

    摘要:我们将登录按钮上绑上事件,点击登录之后向服务端提交账号和密码进行验证。所以前端和后端权限的划分是不太一致。侧边栏最后一个涉及到权限的地方就是侧边栏,不过在前 完整项目地址:vue-element-admin 系列文章: 手摸手,带你用vue撸后台 系列一(基础篇) 手摸手,带你用vue撸后台 系列二(登录权限篇) 手摸手,带你用vue撸后台 系列三 (实战篇) 手摸手,带你用vu...

    不知名网友 评论0 收藏0
  • [开源作品] skadmin 管理系统

    摘要:简介项目基于的前后端分离的管理系统,项目采用分模块开发方式,权限控制采用,基于角色的访问控制,支持数据字典数据权限管理前端菜单支持动态路由,另外还有其他的功能模块日志管理代码生成器系统监控云存储管理系统工具等等。 简介 项目基于 Spring Boot 2.1.0 、 Spring Data JPA、 Spring Security、Redis、Vue的前后端分离的管理系统,项目采用分...

    codergarden 评论0 收藏0
  • vue中如何实现后台管理系统的权限控制

    摘要:二接口访问的权限控制接口权限就是对用户的校验。代码如下按扭权限指令至此为止,权限控制流程就已经完全结束了,在最后我们再看一下完整的权限控制流程图吧五路由控制完整流程图六参考文献手撸后台管理网站之权限控制手摸手,带你用撸后台之权限控制 原文首发于我的博客,欢迎点击查看获得更好的阅读体验~ 一、前言 在广告机项目中,角色的权限管理是卡了挺久的一个难点。首先我们确定的权限控制分为两大部分,其...

    songze 评论0 收藏0
  • vue中如何实现后台管理系统的权限控制

    摘要:二接口访问的权限控制接口权限就是对用户的校验。代码如下按扭权限指令至此为止,权限控制流程就已经完全结束了,在最后我们再看一下完整的权限控制流程图吧五路由控制完整流程图六参考文献手撸后台管理网站之权限控制手摸手,带你用撸后台之权限控制 原文首发于我的博客,欢迎点击查看获得更好的阅读体验~ 一、前言 在广告机项目中,角色的权限管理是卡了挺久的一个难点。首先我们确定的权限控制分为两大部分,其...

    iliyaku 评论0 收藏0
  • vue中如何实现后台管理系统的权限控制

    摘要:二接口访问的权限控制接口权限就是对用户的校验。代码如下按扭权限指令至此为止,权限控制流程就已经完全结束了,在最后我们再看一下完整的权限控制流程图吧五路由控制完整流程图六参考文献手撸后台管理网站之权限控制手摸手,带你用撸后台之权限控制 原文首发于我的博客,欢迎点击查看获得更好的阅读体验~ 一、前言 在广告机项目中,角色的权限管理是卡了挺久的一个难点。首先我们确定的权限控制分为两大部分,其...

    VincentFF 评论0 收藏0

发表评论

0条评论

Aomine

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<