我创建了一个boto功能请求以添加此功能,但与此同时,我将其与django
python应用程序配合使用。这是我自己生成的简单代码。底部是django视图的示例方法,因此您可以看到如何为包含Cloudfront内容的网页设置cookie。
import timefrom boto.cloudfront import CloudFrontConnectionfrom boto.cloudfront.distribution import Distributionfrom config import settingsimport loggingfrom django.template.context import RequestContextfrom django.shortcuts import render_to_responselogger = logging.getLogger('boto')logger.setLevel(logging.CRITICAL) #disable DEBUG logging that's enabled in AWS by default (outside of django)AWS_ACCESS_KEY="AKABCDE1235ABCDEF22A"#SAMPLEAWS_SECRET_KEY="a1wd2sD1A/GS8qggkXK1u8kHlh+BiLp0C3nBJ2wW" #SAMPLEkey_pair_id="APKABCDEF123ABCDEFAG" #SAMPLEDOWNLOAD_DIST_ID = "E1ABCDEF3ABCDE" #SAMPLE replace with the ID of your Cloudfront dist from Cloudfront console############################################def generate_signed_cookies(resource,expire_minutes=5): """ @resource path to s3 object inside bucket(or a wildcard path,e.g. '/blah/*' or '*') @expire_minutes how many minutes before we expire these access credentials (within cookie) return tuple of domain used in resource URL & dict of name=>value cookies """ if not resource: resource = 'images/*' dist_id = DOWNLOAD_DIST_ID conn = CloudFrontConnection(AWS_ACCESS_KEY, AWS_SECRET_KEY) dist = SignedcookiedCloudfrontDistribution(conn,dist_id) return dist.create_signed_cookies(resource,expire_minutes=expire_minutes)############################################class SignedcookiedCloudfrontDistribution(): def __init__(self,connection,download_dist_id,cname=True): """ @download_dist_id id of your Cloudfront download distribution @cname boolean True to use first domain cname, False to use cloudfront domain name, defaults to cname which presumably matches your writeable cookies ( .mydomain.com) """ self.download_dist = None self.domain = None try: download_dist = connection.get_distribution_info(download_dist_id) if cname and download_dist.config.cnames: self.domain = download_dist.config.cnames[0] #use first cname if defined else: self.domain = download_dist.domain_name self.download_dist = download_dist except Exception, ex: logging.error(ex) def get_http_resource_url(self,resource=None,secure=False): """ @resource optional path and/or filename to the resource (e.g. /mydir/somefile.txt); defaults to wildcard if unset '*' @secure whether to use https or http protocol for Cloudfront URL - updateto match your distribution settings return constructed URL """ if not resource: resource = '*' protocol = "http" if not secure else "https" http_resource = '%s://%s/%s' % (protocol,self.domain,resource) return http_resource def create_signed_cookies(self,resource,expire_minutes=3): """ generate the Cloudfront download distirbution signed cookies @resource path to the file, path, or wildcard pattern to generate policy for @expire_minutes number of minutes until expiration return tuple with domain used within policy (so it matches cookie domain), and dict of cloudfront cookies you should set in request header """ http_resource = self.get_http_resource_url(resource,secure=False) #per-file access #NOTE secure should match security settings of cloudfront distribution # http_resource = self.get_http_resource_url("somedir/*") #blanket access to all /somedir files inside my bucket # http_resource = self.get_http_resource_url("*") #blanket access to all files inside my bucket #generate no-whitespace json policy, then base64 enpre & make url safe policy = Distribution._canned_policy(http_resource,SignedcookiedCloudfrontDistribution.get_expires(expire_minutes)) enpred_policy = Distribution._url_base64_enpre(policy) #assemble the 3 Cloudfront cookies signature = SignedcookiedCloudfrontDistribution.generate_signature(policy,private_key_file=settings.AMAZON_PRIV_KEY_FILE) cookies = { "CloudFront-Policy" :enpred_policy, "CloudFront-Signature" :signature, "CloudFront-Key-Pair-Id" :key_pair_id #e.g, APKA..... -> same value you use when you sign URLs with boto distribution.create_signed_url() function } return self.domain,cookies @staticmethod def get_expires(minutes): unixTime = time.time() + (minutes * 60) expires = int(unixTime) #if not converted to int causes Malformed Policy error and has 2 decimals in value return expires @staticmethod def generate_signature(policy,private_key_file=None): """ @policy no-whitespace json str (NOT enpred yet) @private_key_file your .pem file with which to sign the policy return enpred signature for use in cookie """ #sign the policy - pre borrowed from Distribution._create_signing_params() signature = Distribution._sign_string(policy, private_key_file) #now base64 enpre the signature & make URL safe enpred_signature = Distribution._url_base64_enpre(signature) return enpred_signature############################################def sample_django_view_method(request,template="mytemplate.html"): expireLen = 30 #30 minutes s3resource = "somepath_in_my_bucket/afile.mp4" context = {} #variables I'm passing to my html template response = render_to_response(template, context, context_instance=RequestContext(request)) domain,cookies = generate_signed_cookies(s3resource,expire_minutes=expireLen) #TROUBLESHOOTING cookieS: #NOTE - cookie Domain must be a domain you control that spans your app & your Cloudfront CNAME #NOTE - (e.g. if my webapp is www.mydomain.com and my AWS Download Distribution has cname cloud.mydomain.com, cant set cookies from webapp to # www.mydomain.com or localhost.mydomain.com or cloud.mydomain.com and have them work # -> instead set cookies to .mydomain.com to work across sub-domains, you can then verify in request headers to CloudFront that these cookies get passed. # TIP - if you set_cookies from a page with a .mydomain.com suffix, but don't see them get set in Chrome they didn't get set because of permissions - can't set to a diff subdomain or diff base domain # TIP - if you set_cookies and see them in Chrome but don't see them in request headers to Cloudfront, cookie domain is likely too narrow, need to widen to span subdomains base_domain = '.mydomain.com' # NOTE: Sanity check when testing so you can flag any gotchas - I have not fully tested using non-cname urls inside policy vs all possible domains for cookie itself if not domain.endswith(base_domain): logger.warn("This likely won't work - your resource permissions use a different domain than your cookies") for name,value in cookies.items(): response.set_cookie(name,value=value,httponly=True,domain=base_domain) return response############################################if __name__ == '__main__': domain,cookies = generate_signed_cookies('images/*',expire_minutes=30)
关于我的设置的注意事项:
- 我只需要对已经设置并可以用于签名URL的下载分发进行一项更改:我必须添加一个具有与我的网站匹配的基本域的cname。
我使用了Chrome Web Developer工具:
- 网络:查看在Cloudfront呼叫中发送的请求标头,并查看403 vs 200 /状态/响应大小
- 控制台:看到403错误,直到一切正常
- 资源> cookie-验证[localhost或您的主机] .mydomain.com cookie是否显示了填充的3个Cloudfront cookie,它们是否设置为Domain = .mydomain.com,并且这些值与Cloudfront的请求标头中的值匹配(如果丢失,可能是域配置错误)
我的AWS配置
- S3需要Cloudfront起源
- Cloudfront下载分布:
- 分布设置:
- cname定义:cloud.mydomain.com(对我来说是新的!)
- 默认的Cloudfront证书
- 来源标签:定义了1个可映射到我的S3存储桶的来源
- 行为标签-默认:
- 所有这些都与我已经使用签名URL的设置相同
- HTTP和HTTPS
- 头
- 转发标题:无
- 使用原始缓存头
- 最小TTL:0
- 转发cookie:无
- 转发查询字符串:否
- 流畅串流:否
- 限制查看者访问权限:是(自已签名的URL以来没有更改)
- 受信任的签名者:自我
拥有上述cookie生成代码后,最棘手的部分是:
- 确保cookie域正确
- 确保策略中的路径/资源与从您的应用发出的请求匹配
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)