同時ログイン禁止(後勝ち)

実装

Spring Web Applicationで同時ログイン禁止(後勝ち)を実装するためには、WebSecurityConfigurerAdapterで以下の記述をする。

Spring Security 使い方メモ セッション管理 - Qiita

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests().antMatchers("/", "/home").permitAll().anyRequest().authenticated()
            .and().formLogin()
                .loginPage("/login").permitAll()
            .and()
                .logout().permitAll()
            .and()
                .sessionManagement().maximumSessions(1)
                .maxSessionsPreventsLogin(false)
                .expiredSessionStrategy(new MySessionInformationExpiredStrategy());
    }
}
public class MySessionInformationExpiredStrategy implements SessionInformationExpiredStrategy {

    @Override
    public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
        DefaultRedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
        redirectStrategy.sendRedirect(event.getRequest(), event.getResponse(), "/login");
    }
}

動作

  1. ブラウザAでログイン
  2. ブラウザBでログイン
  3. ブラウザAでログイン後ページを更新 ブラウザAはログイン画面に遷移する。

ただし、ブラウザのタブで同時ログインした場合は、同じセッションIDを使い回すので、この方法ではできない。

java – Spring Securityで複数のブラウザタブを管理できますか? - コードログ

また、UsernamePassword認証をカスタマイズしている場合、UsernamePassword認証のFilterの方が先に実施されるため、この方法(セッション管理)は期待通りの動きにならない。

UsernamePassword認証Filterより前に実行されるようにできれば良いのだが...。

以下はMySessionInformationExpiredStrategyが実行されている場合のスタックトレースf:id:unokun3:20190519090523p:plain

Headless-Chrome on AWS Lambda

以下の記事を参考にAWS Lambda上でHeadless-Chromeを動かしてみました。

注) Serverlessは事前にインストールしておく必要があります。

AWS Lambda上でのWebクローリング実行に少し近づいてきました。

ファイル構成

適当なディレクトリ以下に二つのディレクトリ(lambda、selenium-layer)を作成していきます。

mkdir crowler(任意)
cd crowler

$ tree -L 2
.
├── lambda
│   ├── handler.py
│   └── serverless.yml
├── selenium-layer
│   ├── chromedriver
│   ├── selenium
│   └── serverless.yml

selenium-layer

selenim(pythonモジュール)とchromedriver(chromedriver, headless-chrome)をLayerとして登録します。

参照した記事は、chromedriverディレクトリ以下の構成が少しわかりにくかったです。

chromedriver

$ cd selenium-layer
$ mkdir chromedriver
$ cd chromedriver

# headless-chromiumダウンロード
$ curl -SL https://github.com/adieuadieu/serverless-chrome/releases/download/v1.0.0-41/stable-headless-chromium-amazonlinux-2017-03.zip > headless-chromium.zip
$ unzip headless-chromium.zip
$ rm headless-chromium.zip

# chromedriverダウンロード
$ curl -SL https://chromedriver.storage.googleapis.com/2.37/chromedriver_linux64.zip > chromedriver.zip
$ unzip chromedriver.zip
$ rm chromedriver.zip

$ tree
.
├── chromedriver(実行モジュール)
└── headless-chromium(実行モジュール)

selemium

pythonモジュールを追加します。

$ cd selenium-layer
$ mkdir selenium
$ cd selenium
$ pip install -t selenium/python/lib/python3.6/site-packages selenium
$ tree -L 3
.
└── python
    └── lib
        └── python3.6

serverless.yml

chromedriverとseleniumをLayer定義します。

$ cat serverless.yml
service: selenium-layer

provider:
  name: aws
  runtime: python3.6
  stage: dev
  region: ap-northeast-1

layers:
  selenium:
    path: selenium
    description: selenium layer
    CompatibleRuntimes:
      - python3.6
  chromedriver:
    path: chromedriver
    description: chrome driver layer
    CompatibleRuntimes:
      - python3.6

resources:
  Outputs:
    SeleniumLayerExport:
      Value:
        Ref: SeleniumLambdaLayer
      Export:
        Name: SeleniumLambdaLayer
    ChromedriverLayerExport:
      Value:
        Ref: ChromedriverLambdaLayer
      Export:
        Name: ChromedriverLambdaLayer

deploy

deployします。awscliのインストールおよび設定は事前に済ませておく必要があります。

$ serverless deploy

AWSコンソールで登録内容を確認することができます。

lambda

登録したselenium-layerを使う関数をLambdaに登録します。

handler.py

Lambda登録したモジュールは/opt以下に配置されます。

$ cat handler.py
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

def hello(event, context):
    options = Options()
    options.binary_location = '/opt/headless-chromium'
    options.add_argument('--headless')
    options.add_argument('--no-sandbox')
    options.add_argument('--single-process')
    options.add_argument('--disable-dev-shm-usage')

    driver = webdriver.Chrome('/opt/chromedriver', chrome_options=options)

    driver.get('https://qiita.com/')
    body = f"Blog title is: {driver.title}"

    driver.close();
    driver.quit();

    response = {
        "statusCode": 200,
        "body": body
    }

    return response

serverless.yml

service: crawler-with-selenium

provider:
  name: aws
  runtime: python3.6
  stage: dev
  region: ap-northeast-1
  timeout: 900
  environment:
    SELENIUM_LAYER_SERVICE: selenium-layer

functions:
  hello:
    handler: handler.hello
    layers:
      - ${cf:${self:provider.environment.SELENIUM_LAYER_SERVICE}-${opt:stage, self:provider.stage}.SeleniumLayerExport}
      - ${cf:${self:provider.environment.SELENIUM_LAYER_SERVICE}-${opt:stage, self:provider.stage}.ChromedriverLayerExport}

deploy

$ serverless deploy

実行

$ seleverless invoke -f hello
{
    "statusCode": 200,
    "body": "Blog title is: Qiita"
}

実行した時に以下のエラーが発生しましたが、しばらく時間をおいたら正常に動作しました。deployには少し時間がかかるのかも。

  Serverless Error ---------------------------------------

  The role defined for the function cannot be assumed by Lambda.

Lambda Layers by Serverless

以下の記事を参考にLambda Layerを試してみました。

LambdaのLayerをServerless Frameworkで - Qiita

Lambda Layersとは

Layer化することによりより複雑な処理が実行できるということかな? AWS Lambda レイヤー - AWS Lambda

layer追加

serverlessのnodejs版(hello)にLayerを追加します。

Layerに追加する関数作成

$ cd my-project
$ tree
.
├── handler.js
├── my-layer
│   └── nodejs
│       └── node_modules
│           └── pow
│               └── index.js
├── serverless.yml

serverless.ymlを修正

cat serverless.yml
layers:
  mylayer:
    path: my-layer

deploy

$ serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service my-service.zip file to S3 (1.81 KB)...
Serverless: Uploading service mylayer.zip file to S3 (207 B)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
..................
Serverless: Stack update finished...
Service Information
service: my-service
stage: dev
region: ap-northeast-1
stack: my-service-dev
resources: 6
api keys:
  None
endpoints:
  None
functions:
  hello: my-service-dev-hello
layers:
  mylayer: arn:aws:lambda:ap-northeast-1:881710576594:layer:mylayer:1

deployされているか確認します。

$ aws lambda list-layers
{
    "Layers": [
        {
            "LayerName": "mylayer",
            "LayerArn": "arn:aws:lambda:ap-northeast-1:881710576594:layer:mylayer",
            "LatestMatchingVersion": {
                "LayerVersionArn": "arn:aws:lambda:ap-northeast-1:881710576594:layer:mylayer:1",
                "Version": 1,
                "CreatedDate": "2019-05-04T05:00:56.274+0000"
            }
        }
    ]
}

はじめてのServerless(AWS)

Serverless(AWS)を使ってみました。

AWS Lambda上にクローラーを設置するのがゴールです。

インストール

Serverless Getting Started Guide

$ npm install -g serverless

# shell再読込
$ exec -l $SHELL

# グローバルにインストールしたくない場合には--save-devオプションを付ける
# ただし、パスを通すのが面倒かも
$ npm install --save serverless

プロジェクト作成

Serverless Framework - AWS Lambda Guide - Quick Start

$ serverless create --template aws-nodejs --path my-service
$ cd my-service
$ ls
handler.js         serverless.yml

deploy

awscliのインストールおよびユーザー作成をしておく必要があります。 ユーザーにはadmin権限を追加しました。 必要最小限の権限については調査中です。

serverless.yml修正

regionを追加する。

$ cat serverless.yml
...
region: ap-northeast-1
...

handler.jsの修正は不要です。

deploy

作成したnodejsアプリ(handler.js)をdeployします。

$ serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service my-service.zip file to S3 (1.81 KB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
................
Serverless: Stack update finished...
Service Information
service: my-service
stage: dev
region: ap-northeast-1
stack: my-service-dev
resources: 5
api keys:
  None
endpoints:
  None
functions:
  hello: my-service-dev-hello
layers:
  None

deploy時に以下のエラーが出た場合には、Admin権限を追加してみてください。(xxx,yyy,zzzは適当に読み替えてください)

  ServerlessError: User: arn:aws:iam::xxx:user/yyy is not authorized to perform: cloudformation:DescribeStacks on resource: arn:aws:cloudformation:ap-northeast-1:zzz:stack/my-service-dev/*

実行

$ serverless invoke -f hello
{
    "statusCode": 200,
    "body": "{\n  \"message\": \"Go Serverless v1.0! Your function executed successfully!\",\n  \"input\": {}\n}"
}

AWSコンソール

Lambda上にdeployされていることが確認できます。

f:id:unokun3:20190504110343p:plain
AWS Lambda

リンク

はじめてのServerless(AWS)

Serverless(AWS)を使ってみました。

AWS Lambda上にクローラーを設置するのがゴールです。

インストール

Serverless Getting Started Guide

$ npm install -g serverless

# shell再読込
$ exec -l $SHELL

# グローバルにインストールしたくない場合には--save-devオプションを付ける
# ただし、パスを通すのが面倒かも
$ npm install --save-dev serverless

プロジェクト作成

Serverless Framework - AWS Lambda Guide - Quick Start

$ serverless create --template aws-nodejs --path my-service
$ cd my-service
$ ls
handler.js         serverless.yml

deploy

awscliのインストールおよびユーザー作成をしておく必要があります。 ユーザーにはadmin権限を追加しました。 必要最小限の権限については調査中です。

serverless.yml修正

regionを追加する。

$ cat serverless.yml
...
region: ap-northeast-1
...

handler.jsの修正は不要です。

deploy

作成したnodejsアプリ(handler.js)をdeployします。

$ serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service my-service.zip file to S3 (1.81 KB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
................
Serverless: Stack update finished...
Service Information
service: my-service
stage: dev
region: ap-northeast-1
stack: my-service-dev
resources: 5
api keys:
  None
endpoints:
  None
functions:
  hello: my-service-dev-hello
layers:
  None

deploy時に以下のエラーが出た場合には、Admin権限を追加してみてください。(xxx,yyy,zzzは適当に読み替えてください)

  ServerlessError: User: arn:aws:iam::xxx:user/yyy is not authorized to perform: cloudformation:DescribeStacks on resource: arn:aws:cloudformation:ap-northeast-1:zzz:stack/my-service-dev/*

実行

$ serverless invoke -f hello
{
    "statusCode": 200,
    "body": "{\n  \"message\": \"Go Serverless v1.0! Your function executed successfully!\",\n  \"input\": {}\n}"
}

AWSコンソール

Lambda上にdeployされていることが確認できます。

f:id:unokun3:20190504110343p:plain
AWS Lambda

リンク

AWS CodeCommitを使ってみる

Crawller開発のため以下の本のCodeCommit(2章)から写経しています。

AmazonWebServicesアプリ開発運用入門 | 戌亥 稔, 上迫 淳也, 三上 大輔, 百瀬 吉伸 |本 | 通販 | Amazon

Windows版は、403(Access Forbidden)が出た。 公式の対応も実施してみましたがうまく動きません。 * 認証情報ヘルパーと AWS CodeCommit への HTTPS 接続のトラブルシューティング - AWS CodeCommit

MacOS環境は以下のページを参照したらgit clone成功しました。 このままこの本を読むか思案中。

Python Chalice使ってみました

AWSAPI Gateway/Lambdaを使う便利なツール「Chalice」を使ってみました。 なんのためにIAMを使うのかその意味が少しわかった気がします。

素晴らしい!

Crowller on AWSに役立てたい。