写在前面:本文只水水地讨论如何去登陆一个OAuth平台并获取用户信息,并没有涉及如何实现一个OAuth平台
OpenResty一直是我很看好的后端技术栈:在Nginx的高性能Web服务器基础上,用Lua这个精巧的语言来扩展业务逻辑的编写能力;工具的封装也非常干净好用,看上去挺符合我对“小而美”的理解。
之前用过OpenResty写了一些不太复杂的东西,主要还是偏向业务相关为主。但长久以来我一直想用OpenResty做些更偏基础设施、或者更基础协议方面的东西。一年多前在网上找了一阵子,发现好像没有一个相对精简而独立的OAuth 2库(嗯是的其实是我眼瞎,这个库在两年前就挂在Github上了),便萌生了自己做一个的想法——显然已经被磨磨叽叽地拖延了一年多——一半是因为自己的拖延症一半是因为自己的水平菜。
最近终于不能忍受如此没有效率的自己,擦亮屏幕读文档撸起袖管写代码,还真搞得差不多了。多说无益,放码过来吧!
首先,我们先建一个文件夹来放项目的所有东西:
$ mkdir -p demo/resty/{conf,logs}
$ cd demo
要做一个良心demo,最重要的是大家都跑得起来。所以我这里用Docker来隔离平台上的区别。为了节省大家宝贵的带宽,我贴一个简单的Dockerfile,这个是基于OpenResty官方Alpine版本(原维护人Evan Wies evan@neomantra.net),又扩展了一些我们会需要用到的东西,去掉了几个我们用不到的模块的编译来节省时间。但求能用,不求Dockerfile编写的最佳实践,把下面东西扔进项目根目录的Dockerfile里就好:
# Dockerfile
FROM alpine:latest
# Docker Build Arguments
ARG RESTY_VERSION="1.11.2.3"
ARG RESTY_OPENSSL_VERSION="1.0.2k"
ARG RESTY_PCRE_VERSION="8.39"
ARG RESTY_J="1"
ARG RESTY_CONFIG_OPTIONS="\
--with-http_addition_module \
--with-pcre-jit \
"
# These are not intended to be user-specified
ARG _RESTY_CONFIG_DEPS="--with-openssl=/tmp/openssl-${RESTY_OPENSSL_VERSION} --with-pcre=/tmp/pcre-${RESTY_PCRE_VERSION}"
# 1) Install apk dependencies
# 2) Download and untar OpenSSL, PCRE, and OpenResty
# 3) Build OpenResty
# 4) Cleanup
RUN \
apk add --no-cache --virtual .build-deps \
build-base \
gd-dev \
geoip-dev \
libxslt-dev \
linux-headers \
make \
perl-dev \
readline-dev \
zlib-dev \
&& apk add --no-cache \
gd \
geoip \
libgcc \
libxslt \
zlib \
curl \
perl \
&& cd /tmp \
&& curl -fSL https://www.openssl.org/source/openssl-${RESTY_OPENSSL_VERSION}.tar.gz -o openssl-${RESTY_OPENSSL_VERSION}.tar.gz \
&& tar xzf openssl-${RESTY_OPENSSL_VERSION}.tar.gz \
&& curl -fSL https://ftp.pcre.org/pub/pcre/pcre-${RESTY_PCRE_VERSION}.tar.gz -o pcre-${RESTY_PCRE_VERSION}.tar.gz \
&& tar xzf pcre-${RESTY_PCRE_VERSION}.tar.gz \
&& curl -fSL https://openresty.org/download/openresty-${RESTY_VERSION}.tar.gz -o openresty-${RESTY_VERSION}.tar.gz \
&& tar xzf openresty-${RESTY_VERSION}.tar.gz \
&& cd /tmp/openresty-${RESTY_VERSION} \
&& ./configure -j${RESTY_J} ${_RESTY_CONFIG_DEPS} ${RESTY_CONFIG_OPTIONS} \
&& make -j${RESTY_J} \
&& make -j${RESTY_J} install \
&& cd /tmp \
&& rm -rf \
openssl-${RESTY_OPENSSL_VERSION} \
openssl-${RESTY_OPENSSL_VERSION}.tar.gz \
openresty-${RESTY_VERSION}.tar.gz openresty-${RESTY_VERSION} \
pcre-${RESTY_PCRE_VERSION}.tar.gz pcre-${RESTY_PCRE_VERSION} \
&& apk del .build-deps \
&& ln -sf /dev/stdout /usr/local/openresty/nginx/logs/access.log \
&& ln -sf /dev/stderr /usr/local/openresty/nginx/logs/error.log
# Add additional binaries into PATH for convenience
ENV PATH=$PATH:/usr/local/openresty/luajit/bin/:/usr/local/openresty/nginx/sbin/:/usr/local/openresty/bin/
RUN opm get bungle/lua-resty-session && opm get pintsized/lua-resty-http
如果要图方便,还可以再搞一个docker-compose的配置,不然直接用Docker的原生命令也可以(command里跑的东西后面会提到):
# docker-compose.yml
web:
build: .
ports:
- "80:80"
volumes:
- .:/var/www/demo
command: "sh -c 'openresty -p /var/www/demo/resty && tail -f /var/www/demo/resty/logs/error.log'"
接下来就到了愉快的写(tie)代(pei)码(zhi)时间!把下面的东西扔进 resty/conf/nginx.conf
文件里:
worker_processes 1;
error_log logs/error.log debug;
events { worker_connections 1024; }
http {
server {
listen 80;
location / {
content_by_lua_block {
ngx.say('hello world')
}
}
}
}
现在我们项目文件夹里的东西应该有这些:
$ tree
.
├── Dockerfile
├── docker-compose.yml
└── resty
├── conf
│ └── nginx.conf
└── logs
3 directories, 3 files
激动人心的时刻到了!轻敲 docker-compose up
,整个屏幕就会布满酷炫的容器构建信息。构建完之后,简单测试一下:
$ curl -v localhost
* Rebuilt URL to: localhost/
* Trying ::1...
* connect to ::1 port 80 failed: Connection refused
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: openresty/1.11.2.3
< Date: Fri, 30 Jun 2017 02:51:34 GMT
< Content-Type: text/plain
< Transfer-Encoding: chunked
< Connection: keep-alive
<
hello world
* Connection #0 to host localhost left intact
俗话说,良好的Hello World是成功的一半,现在Demo里Nginx和OpenResty相关的部分都很直接,大家应该都能读懂,唯一稍微解释一下的就是compose配置里的那句 openresty -p /var/www/demo
:OpenResty有一个命令 openresty
,和Nginx的 nginx
命令几乎一样,所以说 -p
所做的就是指定启动路径啦:
$ openresty -h
nginx version: openresty/1.11.2.3
Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]
Options:
-?,-h : this help
-v : show version and exit
-V : show version and configure options then exit
-t : test configuration and exit
-T : test configuration, dump it and exit
-q : suppress non-error messages during configuration testing
-s signal : send signal to a master process: stop, quit, reopen, reload
-p prefix : set prefix path (default: /usr/local/openresty/nginx/)
-c filename : set configuration file (default: conf/nginx.conf)
-g directives : set global directives out of configuration file
现在趁自己还在一种兴奋和喜悦之中——赶紧把一些无聊的事情做了:注册一个OAuth App。我在这个项目中会用世界最大的码农交友社区Github的登录来做例子,大家可以翻一下它的新App注册流程,非常简单直观,注册完就会得到对应的Client ID和Client Secret(马赛克部分):
截图最下面的那个URL,是OAuth验证的回调,到时候我们还会用得上。
上部就先写到这里,主要搭建了一个能在Docker里跑起来的OpenResty实例,注册了一个Github的App,剩下还有一个准备工作,就是需要阅读并理解OAuth 2的登录流程,这块大家可以参考阮一峰的一篇旧博客——我知道他在微博上被喷得很厉害,但是这篇博客作为OAuth 2的流程入门还是不错的。