Skip to content

Instantly share code, notes, and snippets.

@petrabarus
Last active November 5, 2021 13:21
Show Gist options
  • Save petrabarus/22ad66f6a0768ace91335bc58eb439f3 to your computer and use it in GitHub Desktop.
Save petrabarus/22ad66f6a0768ace91335bc58eb439f3 to your computer and use it in GitHub Desktop.
Part 3 Using DynamoDB for Session Management in PHP/Yii2 Application
version: '3'
services:
php:
build: .
volumes:
- ~/.composer-docker/cache:/root/.composer/cache:delegated
- ./:/app:delegated
ports:
- '8080:80'
environment:
AWS_REGION: 'ap-southeast-1'
AWS_ACCESS_KEY_ID: 'fake-access-key'
AWS_SECRET_ACCESS_KEY: 'fake-secret-key'
DYNAMODB_SESSION_TABLE_NAME: 'Sessions'
DYNAMODB_ENDPOINT_URL: 'http://localstack:4569'
depends_on:
- localstack
localstack:
image: localstack/localstack
volumes:
- ./bin/localstack-setup.sh:/localstack-setup.sh
ports:
- "4569:4569"
environment:
SERVICES: 'dynamodb'
DEFAULT_REGION: 'ap-southeast-1'
AWS_REGION: 'ap-southeast-1'
AWS_ACCESS_KEY_ID: 'fake-access-key'
AWS_SECRET_ACCESS_KEY: 'fake-secret-key'
#!/usr/bin/env bash
# file: /bin/localstack-setup.sh
echo "Setting Up..."
aws --endpoint-url=http://localhost:4569 \
--region=$AWS_REGION \
dynamodb \
create-table --table-name Sessions \
--attribute-definitions AttributeName=id,AttributeType=S \
--key-schema AttributeName=id,KeyType=HASH \
--provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
1> /dev/null
aws --endpoint-url=http://localstack:4569 \
--region=$AWS_REGION \
dynamodb list-tables
<?php
//file: /components/Session.php
namespace app\components;
use yii\web\Session as BaseSession;
use Aws\DynamoDb\DynamoDbClient;
class Session extends BaseSession {
private $client;
public $clientConfigs = [];
public $sessionConfigs = [];
public function init()
{
$this->createDynamoDbClient();
parent::init();
}
protected function registerSessionHandler()
{
$configs = array_filter($this->sessionConfigs);
$this->handler = $this->client->registerSessionHandler($configs);
parent::registerSessionHandler();
}
private function createDynamoDbClient()
{
$configs = array_filter($this->clientConfigs);
$this->client = new DynamoDbClient($configs);
}
}
<?php
//file /controllers/TestController.php
namespace app\controllers;
use Yii;
use yii\web\Controller;
class TestController extends Controller {
public function actionIndex($name = '') {
$sessionId = Yii::$app->session->id;
if (!empty($name)) {
Yii::$app->session->set('name', $name);
}
$name = Yii::$app->session->get('name');
return "My name is {$name}. My session ID is: {$sessionId}";
}
}
<?php
//file: /config/web.php
$params = require __DIR__ . '/params.php';
$db = require __DIR__ . '/db.php';
$config = [
'id' => 'basic',
'basePath' => dirname(__DIR__),
'bootstrap' => ['log'],
'aliases' => [
'@bower' => '@vendor/bower-asset',
'@npm' => '@vendor/npm-asset',
],
'components' => [
'request' => [
// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
'cookieValidationKey' => 'dFq59wCiBJbanLg794ATD34bQNZIrCLf',
],
'cache' => [
'class' => 'yii\caching\FileCache',
],
'user' => [
'identityClass' => 'app\models\User',
'enableAutoLogin' => true,
],
'errorHandler' => [
'errorAction' => 'site/error',
],
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
// send all mails to a file by default. You have to set
// 'useFileTransport' to false and configure a transport
// for the mailer to send real emails.
'useFileTransport' => true,
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
'db' => $db,
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
],
],
'session' => [
'class' => app\components\Session::class,
'clientConfigs' => [
'version' => '2012-08-10',
'region' => $_ENV['AWS_REGION'],
'endpoint' => $_ENV['DYNAMODB_ENDPOINT_URL'] ?? null
],
'sessionConfigs' => [
'table_name' => $_ENV['DYNAMODB_SESSION_TABLE_NAME']
]
]
],
'params' => $params,
];
if (YII_ENV_DEV) {
// configuration adjustments for 'dev' environment
$config['bootstrap'][] = 'debug';
$config['modules']['debug'] = [
'class' => 'yii\debug\Module',
// uncomment the following to add your IP if you are not connecting from localhost.
//'allowedIPs' => ['127.0.0.1', '::1'],
];
$config['bootstrap'][] = 'gii';
$config['modules']['gii'] = [
'class' => 'yii\gii\Module',
// uncomment the following to add your IP if you are not connecting from localhost.
//'allowedIPs' => ['127.0.0.1', '::1'],
];
}
return $config;
//file /cdk/webapp.ts
import cdk = require('@aws-cdk/core');
import ecs = require("@aws-cdk/aws-ecs");
import ecsPatterns = require("@aws-cdk/aws-ecs-patterns");
import ecr = require('@aws-cdk/aws-ecr');
import dynamodb = require('@aws-cdk/aws-dynamodb')
import { Cluster } from './cluster';
interface WebAppProps {
readonly cluster: Cluster;
}
class WebApp extends cdk.Construct {
private fargateService: ecsPatterns.ApplicationLoadBalancedFargateService;
private sessionTable: dynamodb.Table;
public readonly service: ecs.IBaseService;
public readonly containerName: string;
public readonly ecrRepo: ecr.Repository;
constructor(scope: cdk.Construct, id: string, props: WebAppProps) {
super(scope, id);
this.ecrRepo = new ecr.Repository(this, 'ECRRepo');
this.sessionTable = this.createSessionTable();
this.fargateService = this.createService(props.cluster.ecsCluster);
this.service = this.fargateService.service;
this.containerName = this.fargateService.taskDefinition.defaultContainer!.containerName;
this.grantPermissions();
this.addAutoScaling();
this.output();
}
private createService(cluster: ecs.Cluster) {
const region = cdk.Stack.of(this).region;
return new ecsPatterns.ApplicationLoadBalancedFargateService(this, 'Service', {
cluster: cluster,
taskImageOptions: {
image: ecs.ContainerImage.fromAsset('.'),
environment: {
AWS_REGION: region,
DYNAMODB_SESSION_TABLE_NAME: this.sessionTable.tableName,
}
},
});
}
private addAutoScaling() {
const autoScalingGroup = this.fargateService.service.autoScaleTaskCount({
minCapacity: 2,
maxCapacity: 10
});
autoScalingGroup.scaleOnCpuUtilization('CpuScaling', {
targetUtilizationPercent: 50,
scaleInCooldown: cdk.Duration.seconds(60),
scaleOutCooldown: cdk.Duration.seconds(60),
});
}
private createSessionTable(): dynamodb.Table {
return new dynamodb.Table(this, 'Sessions', {
partitionKey: {
name: 'id',
type: dynamodb.AttributeType.STRING,
}
});
}
private grantPermissions() {
const taskDefinition = this.fargateService.taskDefinition;
this.ecrRepo.grantPull(taskDefinition.executionRole!);
const actions = [
"dynamodb:GetItem",
"dynamodb:UpdateItem",
"dynamodb:DeleteItem",
"dynamodb:Scan",
"dynamodb:BatchWriteItem"
]
this.sessionTable.grant(taskDefinition.taskRole, ...actions);
}
private output() {
new cdk.CfnOutput(this, 'ECRRepoURI', {value: this.ecrRepo.repositoryUri});
new cdk.CfnOutput(this, 'ServiceName', {value: this.service.serviceName});
new cdk.CfnOutput(this, 'ContainerName', {value: this.containerName});
new cdk.CfnOutput(this, 'SessionTableName', {value: this.sessionTable.tableName});
}
}
export {WebApp, WebAppProps};
@srakl
Copy link

srakl commented Jul 25, 2021

would using dynamodb solve this issue? yiisoft/yii2-authclient#324

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment