カテゴリー
【Rxjs基礎講座】rxjs#ajaxでCookie付きのログイン認証を行う
※ 当ページには【広告/PR】を含む場合があります。
2020/02/27
2022/10/05
Promise
fromPromise
ajax
前準備(ビルド環境等)
xmlhttprequestのインストール
$ yarn add xmlhttprequest
rxjs/ajaxオペレーターの使い方の基本
$ tree -I node_modules
.
├── dist
│ ├── index.d.ts
│ ├── index.js
│ └── index.js.map
├── index.ts
├── package.json
├── tsconfig.json
└── yarn.lock
src
ajax.ts
$ mkdir src && touch src/ajax.ts
$ tree -I node_modules
.
├── dist
│ ├── index.d.ts
│ ├── index.js
│ └── index.js.map
├── index.ts
├── package.json
├── src
│ └── ajax.ts
├── tsconfig.json
└── yarn.lock
tsconfig.json
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"declaration": true,
"sourceMap": true,
"outDir": "./dist",
"strict": true,
"moduleResolution": "node",
"esModuleInterop": true
},
"include": [
"./index.ts",
"./src/*" // 👈 Add it here
],
"compileOnSave": false
}
ajax.ts
import { ajax } from 'rxjs/ajax';
const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
export const ajax$ = ajax({
createXHR: () => new XMLHttpRequest(),
url: 'https://www.google.com/',
method: 'GET',
responseType: 'text'
});
index.ts
import { Observable } from 'rxjs';
import { ajax$ } from './src/ajax';
ajax$.subscribe(
res => console.log(res),
err => console.log(err)
);
$ tsc && babel-node dist/index.js
AjaxResponse {
originalEvent: undefined,
xhr: {
UNSENT: 0,
OPENED: 1,
HEADERS_RECEIVED: 2,
LOADING: 3,
DONE: 4,
readyState: 4,
...中略
</body></html>\"
}
AjaxResponse
rxjs/ajaxによるCookieによるログイン機能の実装
テストサイト(の候補)
Web Scraper Testing Ground
demo-admin
demo9999
typescriptによるログインメソッドの実装
src
login.ts
$ touch src/login.ts
login.ts
import { Observable } from 'rxjs';
import { ajax } from 'rxjs/ajax';
import { map } from 'rxjs/operators';
const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
export function login$(): Observable<any> {
const usr = 'admin';
const pwd = ''; // 👈 It's wrong on purpose...
// const pwd = '12345';
const playgroud = `http://testing-ground.scraping.pro/login?mode=login`;
const xhr = () => {
const _xhr = new XMLHttpRequest();
return _xhr;
};
const login$ = ajax({
createXHR: xhr,
url: playgroud,
crossDomain: true,
withCredentials: true,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: {
usr: `${usr}`,
pwd: `${pwd}`,
},
responseType: 'text',
timeout: 3000,
async: false // 👈 Important to recieve cookie!
}).pipe(
map(res => res.response)
);
return login$;
}
index.ts
import { Observable } from 'rxjs';
import { login$ } from './src/login';
login$().subscribe(
res => console.log(res),
err => console.log(err),
);
$ tsc && babel-node dist/index.js
<!DOCTYPE html>
#......中略
<div id="case_login">
<h3 class='error'>ACCESS DENIED!</h3><a href='login'><< GO BACK</a></div>
<br/><br/><br/>
</div>
</body>
</html>
ACCESS DENIED!
login.ts
// const pwd = ''; // 👈 It's wrong on purpose...
const pwd = '12345';
$ tsc && babel-node dist/index.js
<!DOCTYPE html>
#....中略
<div id="case_login">
<h3 class='success'>REDIRECTING...</h3><a href='login'><< GO BACK</a></div>
<br/><br/><br/>
</div>
</body>
</html>
REDIRECTING...
Cookieを受け取る
login.ts
//......中略
export function login$(): Observable<any> {
const usr = 'admin';
const pwd = '12345';
const playgroud = `http://testing-ground.scraping.pro/login?mode=login`;
const xhr = () => {
const _xhr = new XMLHttpRequest();
return _xhr;
};
const login$ = ajax({
createXHR: xhr,
url: playgroud,
crossDomain: true,
withCredentials: true,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: {
usr: `${usr}`,
pwd: `${pwd}`,
},
responseType: 'text',
timeout: 3000,
async: false // 👈 Important to recieve cookie!
}).pipe(
map(res => {
const cookie: any = res.xhr.getResponseHeader('Set-Cookie');
const token: string = cookie[0];
return token;
})
);
return login$;
}
xhr.getResponseHeader('Set-Cookie')
login$
$ tsc && babel-node dist/index.js
tdsess=TEST_DRIVE_SESSION
tdsess=TEST_DRIVE_SESSION
サーバー-クライアント間の同期処理
async:false
Cookie送信とログインを試す
src
redirect.ts
$ touch src/redirect.ts
import { Observable } from 'rxjs';
import { ajax } from 'rxjs/ajax';
import { map } from 'rxjs/operators';
const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
export function redirect$(_cookie: string): Observable<any> {
const playgroud = `http://testing-ground.scraping.pro/login?mode=welcome`;
const xhr = () => {
const _xhr = new XMLHttpRequest();
_xhr.setDisableHeaderCheck(true); // important for redirect to send cookie!
return _xhr;
};
const enter_page$ = ajax({
createXHR: xhr,
url: playgroud,
crossDomain: true,
withCredentials: true,
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': _cookie
},
responseType: 'text',
timeout: 3000
}).pipe(
map(res => res.response)
);
return enter_page$;
}
index.ts
import { Observable } from 'rxjs';
import { concatMap } from 'rxjs/operators';
import { login$ } from './src/login';
import { redirect$ } from './src/redirect';
login$().pipe(
concatMap(cookie => redirect$(cookie))
).subscribe(
res => console.log(res),
err => console.log(err)
);
login$
concatMap
redirect$
$ tsc && babel-node dist/index.js
<!DOCTYPE html>
#.......中略
<div id="case_login">
<h3 class='success'>WELCOME :)</h3><a href='login'><< GO BACK</a></div>
<br/><br/><br/>
</div>
</body>
</html>
WELCOME :)
setDisableHeaderCheckメソッド
var forbiddenRequestHeaders = [
"accept-charset",
"accept-encoding",
"access-control-request-headers",
"access-control-request-method",
"connection",
"content-length",
"content-transfer-encoding",
"cookie",
"cookie2",
"date",
"expect",
"host",
"keep-alive",
"origin",
"referer",
"te",
"trailer",
"transfer-encoding",
"upgrade",
"via"
];
cookie
setDisableHeaderCheck
//...
const xhr = () => {
const _xhr = new XMLHttpRequest();
_xhr.setDisableHeaderCheck(true); // important for redirect to send cookie!
return _xhr;
};
//...
まとめ
ajax
ajax
@angular/common/http
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー