Lors du partage d'un fichier volumineux, si le courrier dépasse environ 8 Mo, il sera bloqué car il s'agit d'un serveur de messagerie. Même s'il n'est pas bloqué, l'envoi d'un gros fichier par courrier peut être assez ennuyeux, comme mettre une charge sur le serveur. Donc, je souhaite utiliser le service de stockage, mais s'il s'agit d'un vol de fichier Giga, je suis susceptible de me mettre en colère contre l'accord de sécurité (je l'ai beaucoup utilisé par le passé), et Google Drive s'inquiète du partage sans compte Google (accès si je ne connais pas l'URL Bien que ce ne soit pas possible, il est difficile pour tout le monde d'y accéder).
Tout ce que je veux, c'est une URL qui me permet d'appliquer temporairement un identifiant et de passer et de partager un gros fichier ... (supprimez-le après la fin ou rendez-le privé une fois le délai écoulé)
Donc, j'ai récemment reçu SAA de aws, et je me suis mis au défi de créer un mécanisme pour partager facilement des fichiers avec aws en tant que critique, ce qui était la raison de cet article.
Personnellement, je ne voulais pas allumer / éteindre le serveur ou le surveiller, alors je me suis demandé si je pouvais le construire sans serveur.
À propos, la taille du fichier que vous souhaitez partager est un fichier zip d'environ 100 Mo.
API Gateway
Pour publier Lambda et appliquer l'authentification de base à l'URL publiée. Après vérification, API Gateway dispose d'une méthode pour s'authentifier avec une clé d'accès et une fonction appelée «API Gateway Lambda Authorizer» qui peut préparer Lambda et contrôler l'accès à l'API qui l'utilise.
Lambda
Préparez une fonction Lambda qui applique l'authentification de base pour utiliser «API Gateway Lambda Authorizer» et préparez deux pages pour le téléchargement du fichier zip après l'authentification de base avec la fonction Lambda.
La première consiste à afficher du HTML et à leur demander de sélectionner le fichier à télécharger. Au début, je pensais que ce serait bien de télécharger si je marchais sur l'URL, mais que se passe-t-il s'il y a plusieurs fichiers? J'ai donc décidé de préparer une page HTML. (Quand j'y pense maintenant, je suis content d'avoir utilisé le paramètre de requête. Oui ... → J'ai pensé, mais cela n'a pas fonctionné. Voir ci-dessous.)
L'autre est une fonction Lambda qui télécharge des fichiers depuis S3 et renvoie un fichier zip (binaire).
S3
Utilisez-le comme emplacement pour stocker les fichiers zip que vous souhaitez télécharger et comme emplacement pour stocker les modèles HTML.
TODO: créer et coller un diagramme
Lambda
Nom de la fonction: download ___ auth
lambda pour effectuer l'authentification de base
import json
import os
import base64
def lambda_handler(event, context):
policy = {
'principalId': 'user',
'policyDocument': {
'Version': '2012-10-17',
'Statement': [
{
'Action': 'execute-api:Invoke',
'Effect': 'Deny',
'Resource': event['methodArn']
}
]
}
}
if not basic_auth(event):
print('Auth Error!!!')
return policy
policy['policyDocument']['Statement'][0]['Effect'] = 'Allow'
return policy
def basic_auth(event):
if 'headers' in event.keys() and 'authorization' in event['headers'].keys():
auth_header = event['headers']['authorization']
#Obtenir des informations à partir des variables d'environnement lambda.
user = os.environ['USER']
password = os.environ['PASSWORD']
print(os.environ)
_b64 = base64.b64encode('{}:{}'.format(user, password).encode('utf-8'))
auth_str = 'Basic {}'.format(_b64.decode('utf-8'))
return auth_header == auth_str
raise Exception('Auth Error!!!')
Nom de la fonction: download ___ index
Un lambda qui affiche les fichiers téléchargeables en HTML. Le modèle HTML est obtenu à partir de S3. Le moteur de modèle est jinja.
from jinja2 import Template
import boto3
from botocore.exceptions import ClientError
import os
import logging
logger = logging.getLogger()
S3 = boto3.resource('s3')
TEMPLATE_AWS_S3_BUCKET_NAME = 'hogehoge-downloader'
BUCKET = S3.Bucket(TEMPLATE_AWS_S3_BUCKET_NAME)
def get_object(bucket, object_name):
"""Retrieve an object from an Amazon S3 bucket
:param bucket_name: string
:param object_name: string
:return: botocore.response.StreamingBody object. If error, return None.
"""
try:
response = bucket.Object(object_name).get()
except ClientError as e:
# AllAccessDisabled error == bucket or object not found
logging.error(e)
return None
# Return an open StreamingBody object
return response['Body'].read()
def main():
index_html = get_object(BUCKET,
os.path.join('template', 'index.html')) \
.decode('utf8')
li_html = get_object(BUCKET,
os.path.join('template', 'file_li.html')) \
.decode('utf8')
index_t = Template(index_html)
insert_list = []
objs = BUCKET.meta.client.list_objects_v2(Bucket=BUCKET.name,
Prefix='files')
for obj in objs.get('Contents'):
k = obj.get('Key')
ks = k.split('/')
if ks[1] == '':
continue
file_name = ks[1]
print(obj.get('Key'))
li_t = Template(li_html)
insert_list.append(li_t.render(
file_url='#',
file_name=file_name
))
output_html = index_t.render(file_li=''.join(insert_list))
return output_html
def lambda_handler(event, context):
output_html = main()
return {
"statusCode": 200,
"headers": {
"Content-Type": 'text/html'
},
"isBase64Encoded": False,
"body": output_html
}
Nom de la fonction: download ___ download
Télécharger le fichier depuis s3 lambda
import boto3
from botocore.exceptions import ClientError
import os
import logging
import base64
logger = logging.getLogger()
S3 = boto3.resource('s3')
TEMPLATE_AWS_S3_BUCKET_NAME = 'hogehoge-downloader'
TEMPLATE_BUCKET = S3.Bucket(TEMPLATE_AWS_S3_BUCKET_NAME)
def get_object(bucket, object_name):
"""Retrieve an object from an Amazon S3 bucket
:param bucket_name: string
:param object_name: string
:return: botocore.response.StreamingBody object. If error, return None.
"""
try:
response = bucket.Object(object_name).get()
except ClientError as e:
# AllAccessDisabled error == bucket or object not found
logging.error(e)
return None
# Return an open StreamingBody object
return response['Body'].read()
def lambda_handler(event, context):
file_name = event['queryStringParameters']['fileName']
body = get_object(TEMPLATE_BUCKET, os.path.join('files', file_name))
return {
"statusCode": 200,
"headers": {
"Content-Disposition": 'attachment;filename="{}"'.format(file_name),
"Content-Type": 'application/zip'
},
"isBase64Encoded": True,
"body": base64.b64encode(body).decode('utf-8')
}
API Gateway
--Sélectionnez l'API REST comme type d'API
Construit comme ça.
Défini pour fonctionner avec la fonction lambda qui effectue l'authentification de base.
Réglez comme suit. Veillez à décocher le cache d'autorisation. (Si vous le laissez coché et définissez plusieurs ressources, il se comportera étrangement)
Ceci termine les paramètres d'authentification. Le reste est OK si vous le définissez avec chaque méthode.
Préparez une méthode de ressources comme indiqué ci-dessous.
Les paramètres détaillés pour chacun seront expliqués ci-dessous.
/html
Cochez Utiliser l'intégration du proxy lambda. En l'insérant, l'en-tête, etc. peut être défini du côté lambda.
Définissez la demande de méthode pour s'authentifier avec l'authentification de base.
Modifié pour que le HTML puisse être reconnu dans la réponse de la méthode. Modifiez le type de contenu du corps de la réponse en «text / html».
Ceci termine le réglage.
/download
Comme pour le côté HTML, cochez Utiliser l'intégration du proxy lambda.
L'authentification de base est également définie ici.
De plus, comme je souhaite recevoir le nom de fichier à télécharger en tant que paramètre, j'ai défini un paramètre nommé fileName
dans le paramètre de chaîne de requête URL. (Si vous voulez le rendre obligatoire, cochez-le)
Modification du type de contenu de la réponse de la méthode car je souhaite télécharger le fichier zip.
Enfin, ajoutez le type de média binaire dans les paramètres du menu de gauche. En définissant ici le type de contenu cible, la valeur de retour (base64) de lambda sera convertie en binaire. (Cependant, vous devez ajouter Content-type à l'en-tête de la requête ou ʻapplication / zip` pour Accepter)
S3
nom du bucket: Créez hogehoge-downloader
et créez le répertoire suivant.
--files
: stocker les fichiers zip
--template
: Préparer le fichier de modèle HTML
Le modèle HTML est ci-dessous.
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Téléchargeur</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/css/bulma.min.css">
<script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
</head>
<body>
<section class="section">
<div class="container">
<div class="container">
<ul>{{ file_li }}</ul>
</div>
</div>
</section>
</body>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
function download(e) {
const zipUrl = 'https://xxx.aws.com/prod/download?fileName=' + this.filename;
const blob = axios.get(zipUrl, {
responseType: 'blob',
headers: {
Accept: 'application/zip'
},
}).then(response => {
window.URL = window.URL || window.webkitURL;
const uri = window.URL.createObjectURL(response.data);
const link = document.createElement('a');
link.download = this.filename;
link.href = uri;
link.click()
}).catch(error => {
console.log(error);
});
}
var links = Array.from(document.getElementsByClassName('downloadLink'));
links.map(l => l.addEventListener('click', {filename: l.dataset.filename, handleEvent: download}));
</script>
</html>
file_li.html
<li>
<a href="{{ file_url }}" class="downloadLink" data-filename="{{ file_name }}">{{ file_name }}</a>
</li>
Cependant, cette configuration ne fonctionne pas. Je n'ai pas remarqué jusqu'à ce que je me rassemble. .. ..
Je n'ai pas remarqué jusqu'à ce que je me sois réellement assemblé et confirmé l'erreur.
Veuillez consulter cette page.
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/limits.html
Charge utile d'appel (demande et réponse) 6 Mo (synchrone)
Quoi! !! ?? ?? ?? !! !! 6 Mo? ?? ?? !! !! ?? ?? ??
Dead end.
~ Complete ~ </ FONT>
Oui
Seulement EC2. Préparé pour Ubuntu 18.04.
Nous avons préparé l'API Bottle dans le conteneur Python préparé par Docker. Le processus d'authentification de base et de téléchargement du fichier zip est laissé à Bottle.
Téléchargez le fichier zip placé dans le répertoire courant.
app.py
import bottle
#Nom d'utilisateur et mot de passe d'authentification BASIC
USERNAME = "user"
PASSWORD = "pass"
def check(username, password):
u"""
Vérifiez le nom d'utilisateur et le mot de passe pour l'authentification BASIC
@bottle.auth_basic(check)Appliquer dans
"""
return username == USERNAME and password == PASSWORD
@bottle.route("/zip")
@bottle.auth_basic(check)
def zip():
zip_filename = 'files.zip'
with open(zip_filename, 'rb') as f:
body = f.read()
response.content_type = 'application/zip'
response.set_header('Content-Disposition', 'attachment; filename="{}"'.format(zip_filename))
response.set_header('Content-Length', len(body))
response.body = body
return response
if __name__ == '__main__':
bottle.run(host='0.0.0.0', port=80, debug=True)
$ docker run -p 80:80 -v $(pwd):/app -it docker-image-hogehoge python3 /app/app.py
Vous avez maintenant une URL à télécharger même avec une grande capacité (même si cela prend du temps)! !! !! !! !! !! !!
Pour étudier! C'est sans serveur! J'étais enthousiaste, mais j'aurais dû le faire avec EC2 depuis le début. .. .. .. .. .. ..
Recommended Posts