This section introduces how to use function A to access a service configured with access control and use function B to access a third-party service with access control.
Function A uses HTTP triggers to receive a request from external users, and then access function B to obtain the protected resources while processing the request. If function A obtains the resources, it proceeds to process the request. Otherwise, it stops.
Function B also uses HTTP triggers. Function B uses a whitelist to authenticate visitors and returns the requested resources when the visitors are validated. If the visitors fail to pass the authentication, an authentication error is returned.
Use ECS to build a proxy server and use NGINX to provide the proxy service.
Create functions for services A and B
Log on to Function Compute console.
See Service operation to create service A and service B.
In the left-side navigation pane, click and enter the corresponding service page.
Click Create Function in the service, go to the function creation page and perform the following tasks:
Click Select All and choose Python2.7 from the drop-down list. All code in this example is based on Python.
Select Empty Function.
Select No Trigger.
Create the function and specify the service name, function name, description, and runtime.
Click Next.
Make sure that all information is correct and then click Create.
Write code.
Function A is created by using an HTTP trigger. You can directly copy the following code to function A and then click Save.
Function B is created by using the Django framework. Therefore, you must use command-line tool fcli or Python SDK to upload the code package. You can also use Object Storage Service (OSS) or directly upload a ZIP file.
Create an HTTP trigger for both function A and function B.
If you have any issues during HTTP trigger creation, reference the document Samples of HTTP triggers.
Now service A and service B are successfully built. However, you cannot use service A to call service B to obtain permissions because the whitelist in function B only contains the public IP address of the proxy server. The following shows the content of functions A and B.
Write function A
Function A is triggered by using an HTTP trigger.
Write function
Function sample descriptions:
A handler is a function that the system can run when executing the code. It contains the logic for simulating the results of invoking function B with and without using the proxy.
get_data_by_url contains the logic for invoking function B.
my_http_request is used to send HTTP requests through the proxy.
# -*- coding: utf-8 -*-
import logging
import urllib, urllib2, sys
import ssl
import json
# Proxy service address
proxy_address = 'ip:port'
# Function B service address
data_service_host = 'https://{id}.{region}.fc.aliyuncs.com'
data_service_path = '/service/path'
def handler(environ, start_response):
"""
entrance
"""
url = data_service_host + data_service_path
# Use a proxy
proxy_result = get_data_by_url(url, proxy_address)
# Not use a proxy
normal_result = get_data_by_url(url, None)
# Return and display the results of getting data with and without the proxy
result = {
"query_with_proxy_result": proxy_result,
"query_without_proxy_result": normal_result
}
status = '200 OK'
response_headers = [('Content-type', 'text/json')]
start_response(status, response_headers)
return json.dumps(result)
def get_data_by_url(url, proxy):
"""
Encapsulate user requests
"""
result = {
"success": False,
"secret_data": '',
"data_service_raw_data": {}
}
content = my_http_request(url, proxy)
if content:
content = json.loads(content)
result["data_service_raw_data"] = content
# Simulate requested data processing
if "authorized" in content and content["authorized"]:
result["success"] = True
result["secret_data"] = content["protected_data"]
return result
def my_http_request(url, proxy=None):
"""
Request with proxy information
"""
try:
ret = None
socket_fd = None
request = urllib2.Request(url)
request.add_header('User-Agent', 'Fake_browser/1.0')
if proxy:
request.set_proxy(proxy, 'http')
opener = urllib2.build_opener()
socket_fd = opener.open(request)
ret = socket_fd.read()
except Exception as e:
ret = json.dumps({"info": "exception in proxy query: %s" % e})
finally:
if socket_fd:
socket_fd.close()
return ret
Write function B
In function B, use Django to build a Web service and set a whitelist for authentication. Data is returned only when the visitors pass the authentication. The structure of the code is as follows:
project/
├── lib
│ ├── Django-1.11.13.dist-info
│ ├── django
│ ├── pytz
│ └── pytz-2018.4.dist-info
├── main.py
└── src
├── __init__.py
├── bin
│ ├── __init__.py
│ └── manage.py
├── conf
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── data
└── views
├── __init__.py
└── view.py
The code shows the structure of the code package.
Write function
- Function entry
#!/usr/bin/env python
# coding=utf-8
import sys
import os
# load local django
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)) + '/lib')
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "src"))
import django
print (django.__version__)
import views.view
from conf.wsgi import application
def handler(environ, start_response):
import urlparse
parsed_tuple = urlparse.urlparse(environ['fc.request_uri'])
li = parsed_tuple.path.split('/')
global base_path
if not views.view.base_path:
views.view.base_path = "/".join(li[0:5])
return application(environ, start_response)
- urls.py
from django.conf.urls import url
from django.contrib import admin
from views import view
urlpatterns = [
url(r'^index$', view.index),
url(r'^get_data$', view.get_data),
]
- views.py
#!/usr/bin/env python
# coding=utf-8
from django.http import HttpResponse
from django.conf import settings
import logging
import json
logger = logging.getLogger()
base_path = ""
def index(request):
"""
Testing entry
"""
logger.info("Django request detected! url: index")
white_list = settings.WHITE_LIST
allowed_hostlist = ' '
for allowed_host in white_list:
allowed_hostlist += allowed_host
allowed_hostlist += ' '
return HttpResponse("<h1>It works! Copyright: jianyi</h1> Whitelist: %s" % allowed_hostlist, status=200)
def get_data(request):
"""
Operation for obtaining data
"""
result = {
"remote_ip": '',
"white_list": [],
"authorized": False,
"protected_data": ''
}
if request.META.has_key('HTTP_X_FORWARDED_FOR'):
remote_ip = request.META['HTTP_X_FORWARDED_FOR']
else:
remote_ip = request.META['REMOTE_ADDR']
result["remote_ip"] = remote_ip
result["white_list"] = settings.WHITE_LIST
if remote_ip in result["white_list"]:
result["authorized"] = True
result["protected_data"] = "Alibaba"
return HttpResponse(json.dumps(result), status=200)
- settings.py
Add the whitelist setting to the bottom of the default settings.py file: add the public IP address of the proxy server to the whitelist.
# User conf
WHITE_LIST = [
"127.0.0.1",
"xx.xx.xx.xx"
]
Build a proxy
Use NGINX to provide the proxy service. You can deploy NGINX on an ECS instance or a normal server. After the deployment is complete, set the proxy settings in the configuration file as follows:
server{
resolver x.x.x.x;
listen 8080;
location / {
proxy_pass http://$http_host$request_uri;
}
}
Notes:
- Do not include the hostname.
- You must include the resolver (DNS). Replace x.x.x.x in the proxy settings with the IP address of the DNS resolver.
- Do not change NGINX system variables $http_host and $request_uri.
- In the actual environment, we recommend that you use NGINX or Keepalived to build SLB clusters and proxy clusters to provide proxy service. This improves the availability and performance of the system.
To view the DNS resolver information, run the cat /etc/resolv.conf command.
You can start testing after uploading the code of functions A and B and starting NGINX.