日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

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

發(fā)布時(shí)間:2025/7/14 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用service实现登录、权限控制 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>

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

官網(wǎng)對(duì)于登錄、用戶權(quán)限的介紹只有一段簡(jiǎn)單的說明,并沒有詳細(xì)說明如何使用service實(shí)現(xiàn)權(quán)限控制。下面地址是官網(wǎng)的說法:

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是啥東西呢?簡(jiǎn)單講service也是一個(gè)Ember.Object只不過這個(gè)對(duì)象與普通的對(duì)象有點(diǎn)不一樣。首先這種對(duì)象是放在文件夾appName/app/services目錄下。其次放在這個(gè)目錄下的對(duì)象Ember會(huì)自動(dòng)注冊(cè)(registered)或者注入(injection)到Ember項(xiàng)目中。這種對(duì)象有如下2個(gè)特點(diǎn)

  • 對(duì)象聲明周期是session級(jí)別的
  • 在Ember項(xiàng)目的任何地方都可以調(diào)用
  • 正是基于這兩個(gè)特性才能實(shí)現(xiàn)權(quán)限的控制。最簡(jiǎn)單的例子就是用戶的登錄問題。目前也有現(xiàn)成的插件實(shí)現(xiàn)權(quán)限的控制,請(qǐng)看使用ember-simple-auth實(shí)現(xiàn)Ember.js應(yīng)用的權(quán)限控制所描述的方法,但是如果要根據(jù)自己項(xiàng)目需要去實(shí)現(xiàn)權(quán)限控制那么又如何做呢?

    本篇博文將為你介紹如何使用service實(shí)現(xiàn)權(quán)限控制,我會(huì)創(chuàng)建一個(gè)簡(jiǎn)單的登錄示例加以說明。如有不妥歡迎留言指正。

    構(gòu)建項(xiàng)目

    ember new secretcodez cd secretcodez ember s

    驗(yàn)證項(xiàng)目是否創(chuàng)建成功http://localhost:4200。看到Welcome to Ember說明項(xiàng)創(chuàng)建成功。下面創(chuàng)建演示所需文件。

    創(chuàng)建文件

    ember g route secret ember g route login ember g route applicationember g component secret-page ember g component login-pageember g model code description:stringember g adapter application

    項(xiàng)目演示用到的文件基本就這些。

    secret頁(yè)面

    {{! 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>

    后端服務(wù)

    為了測(cè)試創(chuàng)建一個(gè)簡(jiǎn)單的后端服務(wù)程序,使用的是Node,然后寫死一些測(cè)試數(shù)據(jù)。就沒必要?jiǎng)优5?#xff0c;創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)了!

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

    執(zhí)行完ember g server后,在APP目錄下創(chuàng)建一個(gè)nodejs程序,自動(dòng)植入到當(dāng)前項(xiàng)目中,訪問的domain和port與ember訪問域名端口一致。

    打開index.js編輯后端請(qǐng)求監(jiān)聽。

    // server/index.jsconst 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: '為了測(cè)試創(chuàng)建一個(gè)簡(jiǎn)單的后端服務(wù)程序,使用的是Node,然后寫死一些測(cè)試數(shù)據(jù)。就沒必要?jiǎng)优5?#xff0c;創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)了!' },{ id:2, description: '本篇博文將為你介紹如何使用service實(shí)現(xiàn)權(quán)限控制,我會(huì)創(chuàng)建一個(gè)簡(jiǎn)單的登錄示例加以說明。如有不妥歡迎留言指正。' }]});});};

    既然用到自己的后端服務(wù)那么對(duì)應(yīng)的你就需要自定義適配器了。簡(jiǎn)單起見就創(chuàng)建RESTAdapter適配器吧。JSONAPIAdapter適配器相對(duì)麻煩點(diǎn),需要格式化數(shù)據(jù)為json api。

    // app/adapters/application.jsexport default DS.RESTAdapter.extend({namespace: 'api' });

    使用屬性namespace指定URL前綴,比如請(qǐng)求URL為http://localhost:4200/api/codes,自動(dòng)在請(qǐng)求上加入前綴api。

    修改路由,獲取后端數(shù)據(jù)。

    // app/routes/secret.jsexport default Ember.Route.extend({model() {// 返回后端數(shù)據(jù),這些數(shù)據(jù)直接從 server/index.js 獲取return this.store.findAll('code');} });

    重新啟動(dòng)項(xiàng)目。檢查項(xiàng)目是否有錯(cuò)誤!如果啟動(dòng)沒問題,那么訪問http://localhost:4200/secret你也會(huì)得到如下截圖的效果。

    從截圖中可以看到發(fā)送一個(gè)請(qǐng)求http://localhost:4200/api/codes,并且從這個(gè)請(qǐng)求中獲取到服務(wù)端返回的數(shù)據(jù)。你可以直接把這個(gè)URL放到瀏覽器地址欄執(zhí)行,可以清楚的看到返回的數(shù)據(jù)。數(shù)據(jù)的格式是普通的json格式。

    目前的效果是任何人都可以訪問,還沒實(shí)現(xiàn)權(quán)限控制的效果。那么如何去實(shí)現(xiàn)呢?不知道你是否看過前面的文章adapter與serializer使用示例,如果你看過里面有介紹過在請(qǐng)求頭加驗(yàn)證信息這個(gè)小結(jié)。如果我也想這么實(shí)現(xiàn)控制訪問API的權(quán)限如何做呢?

    修改服務(wù)端,加入權(quán)限校驗(yàn)

    // 攔截 /api/codes 請(qǐng)求 app.get('/api/codes', function(req, res) {//獲取數(shù)據(jù)之前先校驗(yàn)請(qǐng)求者是否有權(quán)訪問資源// 做一個(gè)非常簡(jiǎn)單的判斷,如果請(qǐng)求的頭信息不等于BLOG.DDLISTING.COM則認(rèn)為無權(quán)限if (req.headers['authorization'] !== 'BLOG.DDLISTING.COM') {return res.status(403).send('您無權(quán)訪問此資源!')}// 直接返回正確狀態(tài)和測(cè)試數(shù)據(jù)return res.status(200).send({codes: [{ id:1, description: '為了測(cè)試創(chuàng)建一個(gè)簡(jiǎn)單的后端服務(wù)程序,使用的是Node,然后寫死一些測(cè)試數(shù)據(jù)。就沒必要?jiǎng)优5?#xff0c;創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)了!' },{ id:2, description: '本篇博文將為你介紹如何使用service實(shí)現(xiàn)權(quán)限控制,我會(huì)創(chuàng)建一個(gè)簡(jiǎn)單的登錄示例加以說明。如有不妥歡迎留言指正。' }]}); })

    注意:代碼只列出主要部分,其他的不變。 在代碼中加入了簡(jiǎn)單的權(quán)限校驗(yàn),通常authorization的值應(yīng)該是變化的或者是每個(gè)用戶都是唯一的,比如oauth2中的access token。當(dāng)你再次訪問之前的資源http://localhost:4200/secret可以看到,報(bào)錯(cuò)了,提示無權(quán)訪問。如下截圖:

    顯然這樣的校驗(yàn)是沒啥意義的,那么如果你也想模擬Oauth2也生成一個(gè)唯一的access token,你可以請(qǐng)求之前首先獲取一個(gè)access token。但是這個(gè)access token不是隨便就能獲取的,需要通過登錄成功后才能獲取到。下面加入模擬登錄的程序。仍然是修改server/index.js。

    // 登錄 app.post('/api/login', function(req, res) {//判斷用戶名和密碼是否正確,這里就直接判斷字符串了,實(shí)際中通常是通過查詢數(shù)據(jù)去判斷登錄的用戶是否存在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錯(cuò)誤!' });} });

    有了后端的服務(wù)之后顯然我們需要在前端增加一個(gè)登錄的表單,提供用戶登錄并且登錄成功之后還要把獲取到的access_token保存好,在發(fā)送請(qǐng)求的時(shí)候設(shè)置到請(qǐng)求的頭。這個(gè)時(shí)候就需要用到service了!!

    登錄

    登錄表單

    {{! app/templates/login.hbs 登錄}} {{login-page}} {{! app/templates/components/login-page.hbs 登錄表單}}{{link-to '點(diǎn)擊查看有權(quán)才能訪問的資源' ’secret}}<h2>登錄</h2> <p>默認(rèn)的用戶名和密碼為: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.jsimport Ember from 'ember';export default Ember.Component.extend({authManager: Ember.inject.service(), //注入servi'auth-manager'ceactions: {authenticate() {const { username, password } = this.getProperties('username', 'password');//調(diào)用service類中的authenticate方法校驗(yàn)登錄的用戶this.get('authManager').authenticate(username, password),then(() => {console.log('登錄成功');}, (err) => {console.log('登錄失敗');});}} });

    在這個(gè)類中使用了service類,并且調(diào)用此類中的authenticate方法。代碼中的屬性authManager就是一個(gè)service實(shí)例。下面定義service類。

    ember g service auth-manager // app/serivces/auth-manager.jsimport Ember from 'ember';export default Ember.Service.extend({accessToken: null,// 判斷accessToken是否是空isAuthenticated: Ember.computed.bool('accessToken'),// 發(fā)起請(qǐng)求校驗(yàn)登錄用戶authenticate(username, password) {return Ember.$.ajax({method: 'post',url: '/api/login',data: { username: username, password: password }}).then((res) => {// 設(shè)置返回的access_token到service類的屬性中this.set('accessToken', res.access_token);}, (err) => {//登錄失敗});},invalidate() {this.set('accessToken', null);} });

    在組件類login-page.js中并沒有直接發(fā)請(qǐng)求校驗(yàn)用戶是否登錄成功,而是通過調(diào)用serivce類的方法去校驗(yàn),目的是為了把返回的值保存到service的屬性中,這也是利用它的特性。方法invalidate的目的是執(zhí)行退出登錄操作,把保存到service屬性中的值置空,使得計(jì)算屬性isAuthenticated返回false。

    一切都定義好了下面就是如何使用這個(gè)service屬性了!修改適配器的代碼,在請(qǐng)求頭中加入accessToken。

    // import JSONAPIAdapter from 'ember-data/adapters/json-api'; import DS from 'ember-data';// 不使用默認(rèn)適配器JSONAPIAdapter,而是使用RESTAdapter export default DS.RESTAdapter.extend({namespace: 'api', //訪問請(qǐng)求前綴: http://localhost:4200/api/codes// 加入請(qǐng)求頭authManager: Ember.inject.service('auth-manager'),headers: Ember.computed('authManager.accessToken', function() {//動(dòng)態(tài)返回accessToken的值return {'authorization': `${this.get('authManager.accessToken')}`};}) });

    到此代碼基本寫完了,為了處理服務(wù)端返回的錯(cuò)誤直接在application路由中攔截error事件,在這個(gè)事件中處理錯(cuò)誤的情況。 說明:所有的子路由的error事件都會(huì)自動(dòng)冒泡到路由application的error事件中。

    // app/routes/application.js import Ember from 'ember';export default Ember.Route.extend({actions: {// 處理所有的error事件error(reason, transition) {//如果出現(xiàn)錯(cuò)誤直接轉(zhuǎn)到登錄界面this.transitionTo('login');return false;}} });

    項(xiàng)目重啟完畢(是手動(dòng)終止在啟動(dòng),否則會(huì)出現(xiàn)service未定義的情況)之后可以看到界面直接跳轉(zhuǎn)到了登錄頁(yè)面,實(shí)現(xiàn)了簡(jiǎn)單的權(quán)限攔截(無權(quán)先登錄)。

    未登錄直接點(diǎn)擊鏈接“點(diǎn)擊查看有權(quán)才能訪問的資源”效果

    可以看到瀏覽器控制臺(tái)打印信息顯示資源無權(quán)訪問,返回的代碼是403。

    輸入錯(cuò)誤的用戶名或密碼的情況:

    登錄成功再訪問授權(quán)資源

    登錄成功之后再點(diǎn)擊鏈接可以正常訪問了,并且正確看到后端返回的數(shù)據(jù)。

    即使你點(diǎn)擊鏈接“點(diǎn)擊查看有權(quán)才能訪問的資源”也還是會(huì)跳轉(zhuǎn)回登錄頁(yè)面。那么開始測(cè)試登錄后的效果,在表單中輸入正確的用戶名和密碼。點(diǎn)擊登錄后跳轉(zhuǎn)到了

    退出

    有登錄就會(huì)有退出,退出相對(duì)簡(jiǎn)單,只要銷毀了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({//注入serviceauthManager: Ember.inject.service('auth-manager'),actions: {invalidate() {this.get('authManager').invalidate(); //退出登錄狀態(tài)//暫時(shí)粗暴處理,直接強(qiáng)制刷新,重新進(jìn)入application路由觸發(fā)error事件,再次判斷是否登錄location.reload();}} });

    對(duì)于退出事件的處理就比較簡(jiǎn)單粗暴了,直接刷新頁(yè)面,由于屬性authManager的值已經(jīng)設(shè)置為null所以發(fā)起請(qǐng)求的時(shí)候是無權(quán)限的會(huì)再次觸發(fā)error事件,然后跳轉(zhuǎn)到登錄頁(yè)面。

    到這里,基本上實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的權(quán)限控制功能。例子比較簡(jiǎn)單,但是處理的思路大體上是這樣做的,能實(shí)現(xiàn)這樣的功能是基于service類的特性。也希望讀者能通過本例理解懂得如何使用service。

    項(xiàng)目代碼:https://github.com/ubuntuvim/secretcodez,有疑問歡迎給我留言。 您的支持是我繼續(xù)寫作的最大動(dòng)力,謝謝!!

    轉(zhuǎn)載于:https://my.oschina.net/ubuntuvim/blog/691554

    總結(jié)

    以上是生活随笔為你收集整理的使用service实现登录、权限控制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。