├── config ├── nginx.conf ├── README.md ├── ngx_http_oauth_request_module.c └── ngx_http_oauth_module.c /config: -------------------------------------------------------------------------------- 1 | ngx_addon_name="ngx_http_oauth_module" 2 | HTTP_MODULES="$HTTP_MODULES ngx_http_oauth_module ngx_http_oauth_request_module" 3 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_oauth_module.c \ 4 | $ngx_addon_dir/ngx_http_oauth_request_module.c" 5 | 6 | -------------------------------------------------------------------------------- /nginx.conf: -------------------------------------------------------------------------------- 1 | 2 | upstream hsock_rsrv { 3 | server 192.168.100.133:9998; 4 | keepalive 1024; 5 | } 6 | 7 | upstream hsock_wsrv { 8 | server 192.168.100.133:9999; 9 | keepalive 1024; 10 | } 11 | 12 | server { 13 | listen 80; 14 | 15 | oauth_db some_db; 16 | oauth_table oauth_access_token; 17 | 18 | location /token { 19 | oauth_token hsock_wsrv; 20 | oauth_appid some_appid; 21 | oauth_secret some_secret; 22 | oauth_expires_in 2h; 23 | } 24 | 25 | location /check { 26 | oauth_check hsock_rsrv; 27 | } 28 | 29 | location / { 30 | root html/api; 31 | index index.php; 32 | } 33 | 34 | location ~ \.php$ { 35 | oauth_request /check; 36 | root html/api; 37 | fastcgi_pass 127.0.0.1:9000; 38 | fastcgi_index index.php; 39 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 40 | include fastcgi_params; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nginx-http-oauth-module 2 | 3 | This module can be used for api authentication, is similar like oauth 2 legged authentication. 4 | 5 | ## 1. Install Handlersocket 6 | 7 | https://github.com/DeNA/HandlerSocket-Plugin-for-MySQL 8 | 9 | https://github.com/DeNA/HandlerSocket-Plugin-for-MySQL/blob/master/docs-en/installation.en.txt 10 | 11 | 12 | ## 2. Create Table 13 | 14 | CREATE TABLE `oauth_access_token` ( 15 | 16 | `id` int(10) NOT NULL AUTO_INCREMENT, 17 | 18 | `access_token` varchar(255) DEFAULT NULL, 19 | 20 | `expires_in` int(10) NOT NULL, 21 | 22 | `last_used_time` int(10) NOT NULL, 23 | 24 | PRIMARY KEY (`id`), 25 | 26 | KEY `ACCESS_TOKEN` (`access_token`) 27 | 28 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 29 | 30 | 31 | ## 3. Install Oauth Module 32 | 33 | > cd /work/nginx-1.8.0 && ./configure --add-module=/work/nginx-http-oauth-module && make 34 | 35 | 36 | ## 4. Add Config 37 | 38 | see nginx.conf please 39 | 40 | 41 | ## 5. Using Oauth Module 42 | 43 | a) generate access token 44 | 45 | http://192.168.1.104/token?appid=some_appid&secret=some_secret 46 | 47 | b) check access token 48 | 49 | http://192.168.1.104/api/test.php?access_token=some_access_token 50 | -------------------------------------------------------------------------------- /ngx_http_oauth_request_module.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Maxim Dounin 4 | * Copyright (C) Nginx, Inc. 5 | * Copyright (C) nglua.com 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | typedef struct { 15 | ngx_str_t uri; 16 | } ngx_http_oauth_request_conf_t; 17 | 18 | 19 | typedef struct { 20 | ngx_uint_t done; 21 | ngx_uint_t status; 22 | ngx_http_request_t *subrequest; 23 | } ngx_http_oauth_request_ctx_t; 24 | 25 | 26 | static ngx_int_t ngx_http_oauth_request_handler(ngx_http_request_t *r); 27 | static ngx_int_t ngx_http_oauth_request_done(ngx_http_request_t *r, 28 | void *data, ngx_int_t rc); 29 | static void *ngx_http_oauth_request_create_conf(ngx_conf_t *cf); 30 | static char *ngx_http_oauth_request_merge_conf(ngx_conf_t *cf, 31 | void *parent, void *child); 32 | static ngx_int_t ngx_http_oauth_request_init(ngx_conf_t *cf); 33 | static char *ngx_http_oauth_request(ngx_conf_t *cf, ngx_command_t *cmd, 34 | void *conf); 35 | 36 | 37 | static ngx_command_t ngx_http_oauth_request_commands[] = { 38 | 39 | { ngx_string("oauth_request"), 40 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 41 | ngx_http_oauth_request, 42 | NGX_HTTP_LOC_CONF_OFFSET, 43 | 0, 44 | NULL }, 45 | 46 | ngx_null_command 47 | }; 48 | 49 | 50 | static ngx_http_module_t ngx_http_oauth_request_module_ctx = { 51 | NULL, /* preconfiguration */ 52 | ngx_http_oauth_request_init, /* postconfiguration */ 53 | 54 | NULL, /* create main configuration */ 55 | NULL, /* init main configuration */ 56 | 57 | NULL, /* create server configuration */ 58 | NULL, /* merge server configuration */ 59 | 60 | ngx_http_oauth_request_create_conf, /* create location configuration */ 61 | ngx_http_oauth_request_merge_conf /* merge location configuration */ 62 | }; 63 | 64 | 65 | ngx_module_t ngx_http_oauth_request_module = { 66 | NGX_MODULE_V1, 67 | &ngx_http_oauth_request_module_ctx, /* module context */ 68 | ngx_http_oauth_request_commands, /* module directives */ 69 | NGX_HTTP_MODULE, /* module type */ 70 | NULL, /* init master */ 71 | NULL, /* init module */ 72 | NULL, /* init process */ 73 | NULL, /* init thread */ 74 | NULL, /* exit thread */ 75 | NULL, /* exit process */ 76 | NULL, /* exit master */ 77 | NGX_MODULE_V1_PADDING 78 | }; 79 | 80 | 81 | static ngx_int_t 82 | ngx_http_oauth_request_handler(ngx_http_request_t *r) 83 | { 84 | u_char *p; 85 | ngx_int_t key; 86 | ngx_str_t var; 87 | ngx_str_t *args; 88 | ngx_http_request_t *sr; 89 | ngx_http_variable_value_t *vv; 90 | ngx_http_post_subrequest_t *ps; 91 | ngx_http_oauth_request_ctx_t *ctx; 92 | ngx_http_oauth_request_conf_t *orcf; 93 | 94 | orcf = ngx_http_get_module_loc_conf(r, ngx_http_oauth_request_module); 95 | 96 | if (orcf->uri.len == 0) { 97 | return NGX_DECLINED; 98 | } 99 | 100 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 101 | "oauth request handler"); 102 | 103 | ctx = ngx_http_get_module_ctx(r, ngx_http_oauth_request_module); 104 | 105 | if (ctx != NULL) { 106 | if (!ctx->done) { 107 | return NGX_AGAIN; 108 | } 109 | 110 | if (ctx->status == NGX_HTTP_OK) { 111 | return NGX_OK; 112 | } 113 | 114 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 115 | "auth request unexpected status: %d", ctx->status); 116 | 117 | return NGX_HTTP_NOT_ALLOWED; 118 | } 119 | 120 | ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_oauth_request_ctx_t)); 121 | if (ctx == NULL) { 122 | return NGX_ERROR; 123 | } 124 | 125 | ps = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); 126 | if (ps == NULL) { 127 | return NGX_ERROR; 128 | } 129 | 130 | ps->handler = ngx_http_oauth_request_done; 131 | ps->data = ctx; 132 | 133 | ngx_str_set(&var, "arg_access_token"); 134 | 135 | key = ngx_hash_key(var.data, var.len); 136 | 137 | vv = ngx_http_get_variable(r, &var, key); 138 | 139 | if (vv->not_found) { 140 | return NGX_HTTP_NOT_ALLOWED; 141 | } 142 | 143 | args = ngx_palloc(r->pool, sizeof(ngx_str_t)); 144 | if (args == NULL) { 145 | return NGX_ERROR; 146 | } 147 | 148 | args->len = sizeof("access_token=") - 1 + vv->len; 149 | 150 | args->data = ngx_palloc(r->pool, args->len); 151 | if (args->data == NULL) { 152 | return NGX_ERROR; 153 | } 154 | 155 | p = ngx_copy(args->data, (u_char *) "access_token=", sizeof("access_token=") - 1); 156 | p = ngx_copy(p, vv->data, vv->len); 157 | 158 | if (ngx_http_subrequest(r, &orcf->uri, args, &sr, ps, 159 | NGX_HTTP_SUBREQUEST_WAITED) 160 | != NGX_OK) 161 | { 162 | return NGX_ERROR; 163 | } 164 | 165 | /* 166 | * allocate fake request body to avoid attempts to read it and to make 167 | * sure real body file (if already read) won't be closed by upstream 168 | */ 169 | 170 | sr->request_body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); 171 | if (sr->request_body == NULL) { 172 | return NGX_ERROR; 173 | } 174 | 175 | sr->header_only = 1; 176 | 177 | ctx->subrequest = sr; 178 | 179 | ngx_http_set_ctx(r, ctx, ngx_http_oauth_request_module); 180 | 181 | return NGX_AGAIN; 182 | } 183 | 184 | 185 | static ngx_int_t 186 | ngx_http_oauth_request_done(ngx_http_request_t *r, void *data, ngx_int_t rc) 187 | { 188 | ngx_http_oauth_request_ctx_t *ctx = data; 189 | 190 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 191 | "auth request done s:%d", r->headers_out.status); 192 | 193 | ctx->done = 1; 194 | ctx->status = r->headers_out.status; 195 | 196 | return rc; 197 | } 198 | 199 | 200 | static void * 201 | ngx_http_oauth_request_create_conf(ngx_conf_t *cf) 202 | { 203 | ngx_http_oauth_request_conf_t *conf; 204 | 205 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_oauth_request_conf_t)); 206 | if (conf == NULL) { 207 | return NULL; 208 | } 209 | 210 | /* 211 | * set by ngx_pcalloc(): 212 | * 213 | * conf->uri = { 0, NULL }; 214 | */ 215 | 216 | return conf; 217 | } 218 | 219 | 220 | static char * 221 | ngx_http_oauth_request_merge_conf(ngx_conf_t *cf, void *parent, void *child) 222 | { 223 | ngx_http_oauth_request_conf_t *prev = parent; 224 | ngx_http_oauth_request_conf_t *conf = child; 225 | 226 | ngx_conf_merge_str_value(conf->uri, prev->uri, ""); 227 | 228 | return NGX_CONF_OK; 229 | } 230 | 231 | 232 | static ngx_int_t 233 | ngx_http_oauth_request_init(ngx_conf_t *cf) 234 | { 235 | ngx_http_handler_pt *h; 236 | ngx_http_core_main_conf_t *cmcf; 237 | 238 | cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); 239 | 240 | h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); 241 | if (h == NULL) { 242 | return NGX_ERROR; 243 | } 244 | 245 | *h = ngx_http_oauth_request_handler; 246 | 247 | return NGX_OK; 248 | } 249 | 250 | 251 | static char * 252 | ngx_http_oauth_request(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 253 | { 254 | ngx_http_oauth_request_conf_t *orcf = conf; 255 | 256 | ngx_str_t *value; 257 | 258 | if (orcf->uri.data != NULL) { 259 | return "is duplicate"; 260 | } 261 | 262 | value = cf->args->elts; 263 | 264 | orcf->uri = value[1]; 265 | 266 | return NGX_CONF_OK; 267 | } 268 | -------------------------------------------------------------------------------- /ngx_http_oauth_module.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Igor Sysoev 4 | * Copyright (C) Nginx, Inc. 5 | * Copyright (C) nglua.com 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | typedef struct { 16 | ngx_http_upstream_conf_t upstream; 17 | 18 | ngx_str_t db; 19 | ngx_str_t table; 20 | 21 | ngx_str_t appid; 22 | ngx_str_t secret; 23 | 24 | time_t expires_in; 25 | 26 | ngx_int_t (*create_request)(ngx_http_request_t *r); 27 | ngx_int_t (*process_header)(ngx_http_request_t *r); 28 | } ngx_http_oauth_loc_conf_t; 29 | 30 | 31 | typedef struct { 32 | ngx_uint_t state; 33 | ngx_uint_t parse_state; 34 | 35 | ngx_str_t access_token; 36 | ngx_str_t expires_in; 37 | ngx_str_t last_used_time; 38 | 39 | u_char *access_token_begin; 40 | u_char *access_token_end; 41 | u_char *expires_in_begin; 42 | u_char *expires_in_end; 43 | u_char *last_used_time_begin; 44 | u_char *last_used_time_end; 45 | } ngx_http_oauth_ctx_t; 46 | 47 | 48 | static ngx_int_t ngx_http_oauth_create_request(ngx_http_request_t *r); 49 | static ngx_int_t ngx_http_oauth_reinit_request(ngx_http_request_t *r); 50 | static ngx_int_t ngx_http_oauth_process_header(ngx_http_request_t *r); 51 | static ngx_int_t ngx_http_oauth_filter_init(void *data); 52 | static ngx_int_t ngx_http_oauth_filter(void *data, ssize_t bytes); 53 | static void ngx_http_oauth_abort_request(ngx_http_request_t *r); 54 | static void ngx_http_oauth_finalize_request(ngx_http_request_t *r, 55 | ngx_int_t rc); 56 | 57 | static ngx_int_t ngx_http_oauth_create_request_token_request(ngx_http_request_t *r); 58 | static ngx_int_t ngx_http_oauth_create_check_token_request(ngx_http_request_t *r); 59 | static ngx_int_t ngx_http_oauth_process_request_token_header(ngx_http_request_t *r); 60 | static ngx_int_t ngx_http_oauth_process_check_token_header(ngx_http_request_t *r); 61 | 62 | static ngx_int_t ngx_http_oauth_generate_data(ngx_http_request_t *r); 63 | 64 | static void *ngx_http_oauth_create_loc_conf(ngx_conf_t *cf); 65 | 66 | static void *ngx_http_oauth_create_loc_conf(ngx_conf_t *cf); 67 | static char *ngx_http_oauth_merge_loc_conf(ngx_conf_t *cf, 68 | void *parent, void *child); 69 | 70 | static char* ngx_http_oauth_request_token(ngx_conf_t *cf, ngx_command_t *cmd, 71 | void *conf); 72 | static char* ngx_http_oauth_check_token(ngx_conf_t *cf, ngx_command_t *cmd, 73 | void *conf); 74 | static char* ngx_http_oauth_pass(ngx_conf_t *cf, ngx_http_oauth_loc_conf_t *olcf); 75 | 76 | static ngx_int_t ngx_http_oauth_parse(ngx_http_request_t *r, 77 | ngx_http_oauth_ctx_t *ctx); 78 | 79 | 80 | #define NGX_HTTP_OAUTH_OPEN_INDEX "P\t1\ttest\toauth_access_token\tACCESS_TOKEN\taccess_token,expires_in,last_used_time" 81 | #define NGX_HTTP_OAUTH_RESPONSE_OK "{\"errcode\":\"0\",\"errmsg\":\"ok\"}" 82 | 83 | 84 | static ngx_command_t ngx_http_oauth_commands[] = { 85 | 86 | { ngx_string("oauth_bind"), 87 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 88 | ngx_http_upstream_bind_set_slot, 89 | NGX_HTTP_LOC_CONF_OFFSET, 90 | offsetof(ngx_http_oauth_loc_conf_t, upstream.local), 91 | NULL }, 92 | 93 | { ngx_string("oauth_connect_timeout"), 94 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 95 | ngx_conf_set_msec_slot, 96 | NGX_HTTP_LOC_CONF_OFFSET, 97 | offsetof(ngx_http_oauth_loc_conf_t, upstream.connect_timeout), 98 | NULL }, 99 | 100 | { ngx_string("oauth_send_timeout"), 101 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 102 | ngx_conf_set_msec_slot, 103 | NGX_HTTP_LOC_CONF_OFFSET, 104 | offsetof(ngx_http_oauth_loc_conf_t, upstream.send_timeout), 105 | NULL }, 106 | 107 | { ngx_string("oauth_buffer_size"), 108 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 109 | ngx_conf_set_size_slot, 110 | NGX_HTTP_LOC_CONF_OFFSET, 111 | offsetof(ngx_http_oauth_loc_conf_t, upstream.buffer_size), 112 | NULL }, 113 | 114 | { ngx_string("oauth_read_timeout"), 115 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 116 | ngx_conf_set_msec_slot, 117 | NGX_HTTP_LOC_CONF_OFFSET, 118 | offsetof(ngx_http_oauth_loc_conf_t, upstream.read_timeout), 119 | NULL }, 120 | 121 | { ngx_string("oauth_db"), 122 | NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 123 | ngx_conf_set_str_slot, 124 | NGX_HTTP_LOC_CONF_OFFSET, 125 | offsetof(ngx_http_oauth_loc_conf_t, db), 126 | NULL }, 127 | 128 | { ngx_string("oauth_table"), 129 | NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 130 | ngx_conf_set_str_slot, 131 | NGX_HTTP_LOC_CONF_OFFSET, 132 | offsetof(ngx_http_oauth_loc_conf_t, table), 133 | NULL }, 134 | 135 | { ngx_string("oauth_appid"), 136 | NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 137 | ngx_conf_set_str_slot, 138 | NGX_HTTP_LOC_CONF_OFFSET, 139 | offsetof(ngx_http_oauth_loc_conf_t, appid), 140 | NULL }, 141 | 142 | { ngx_string("oauth_secret"), 143 | NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 144 | ngx_conf_set_str_slot, 145 | NGX_HTTP_LOC_CONF_OFFSET, 146 | offsetof(ngx_http_oauth_loc_conf_t, secret), 147 | NULL }, 148 | 149 | { ngx_string("oauth_expires_in"), 150 | NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 151 | ngx_conf_set_sec_slot, 152 | NGX_HTTP_LOC_CONF_OFFSET, 153 | offsetof(ngx_http_oauth_loc_conf_t, expires_in), 154 | NULL }, 155 | 156 | { ngx_string("oauth_token"), 157 | NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 158 | ngx_http_oauth_request_token, 159 | NGX_HTTP_LOC_CONF_OFFSET, 160 | 0, 161 | NULL }, 162 | 163 | { ngx_string("oauth_check"), 164 | NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 165 | ngx_http_oauth_check_token, 166 | NGX_HTTP_LOC_CONF_OFFSET, 167 | 0, 168 | NULL }, 169 | 170 | ngx_null_command 171 | }; 172 | 173 | 174 | static ngx_http_module_t ngx_http_oauth_module_ctx = { 175 | NULL, /* preconfiguration */ 176 | NULL, /* postconfiguration */ 177 | 178 | NULL, /* create main configuration */ 179 | NULL, /* init main configuration */ 180 | 181 | NULL, /* create server configuration */ 182 | NULL, /* merge server configuration */ 183 | 184 | ngx_http_oauth_create_loc_conf, /* create location configuration */ 185 | ngx_http_oauth_merge_loc_conf /* merge location configuration */ 186 | }; 187 | 188 | 189 | ngx_module_t ngx_http_oauth_module = { 190 | NGX_MODULE_V1, 191 | &ngx_http_oauth_module_ctx, /* module context */ 192 | ngx_http_oauth_commands, /* module directives */ 193 | NGX_HTTP_MODULE, /* module type */ 194 | NULL, /* init master */ 195 | NULL, /* init module */ 196 | NULL, /* init process */ 197 | NULL, /* init thread */ 198 | NULL, /* exit thread */ 199 | NULL, /* exit process */ 200 | NULL, /* exit master */ 201 | NGX_MODULE_V1_PADDING 202 | }; 203 | 204 | 205 | static ngx_int_t 206 | ngx_http_oauth_handler(ngx_http_request_t *r) 207 | { 208 | ngx_int_t rc; 209 | ngx_http_upstream_t *u; 210 | ngx_http_oauth_ctx_t *ctx; 211 | ngx_http_oauth_loc_conf_t *olcf; 212 | 213 | if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { 214 | return NGX_HTTP_NOT_ALLOWED; 215 | } 216 | 217 | rc = ngx_http_discard_request_body(r); 218 | 219 | if (rc != NGX_OK) { 220 | return rc; 221 | } 222 | 223 | if (ngx_http_set_content_type(r) != NGX_OK) { 224 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 225 | } 226 | 227 | if (ngx_http_upstream_create(r) != NGX_OK) { 228 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 229 | } 230 | 231 | u = r->upstream; 232 | 233 | ngx_str_set(&u->schema, "oauth://"); 234 | u->output.tag = (ngx_buf_tag_t) &ngx_http_oauth_module; 235 | 236 | olcf = ngx_http_get_module_loc_conf(r, ngx_http_oauth_module); 237 | 238 | u->conf = &olcf->upstream; 239 | 240 | u->create_request = ngx_http_oauth_create_request; 241 | u->reinit_request = ngx_http_oauth_reinit_request; 242 | u->process_header = ngx_http_oauth_process_header; 243 | u->abort_request = ngx_http_oauth_abort_request; 244 | u->finalize_request = ngx_http_oauth_finalize_request; 245 | 246 | ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_oauth_ctx_t)); 247 | if (ctx == NULL) { 248 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 249 | } 250 | 251 | ngx_http_set_ctx(r, ctx, ngx_http_oauth_module); 252 | 253 | u->input_filter_init = ngx_http_oauth_filter_init; 254 | u->input_filter = ngx_http_oauth_filter; 255 | u->input_filter_ctx = r; 256 | 257 | r->main->count++; 258 | 259 | ngx_http_upstream_init(r); 260 | 261 | return NGX_DONE; 262 | } 263 | 264 | 265 | static ngx_int_t 266 | ngx_http_oauth_create_request(ngx_http_request_t *r) 267 | { 268 | size_t len; 269 | ngx_buf_t *b; 270 | ngx_chain_t *cl; 271 | ngx_http_oauth_loc_conf_t *olcf; 272 | 273 | len = sizeof(NGX_HTTP_OAUTH_OPEN_INDEX) - 1 + sizeof(CRLF) - 1; 274 | 275 | b = ngx_create_temp_buf(r->pool, len); 276 | if (b == NULL) { 277 | return NGX_ERROR; 278 | } 279 | 280 | cl = ngx_alloc_chain_link(r->pool); 281 | if (cl == NULL) { 282 | return NGX_ERROR; 283 | } 284 | 285 | cl->buf = b; 286 | cl->next = NULL; 287 | 288 | r->upstream->request_bufs = cl; 289 | 290 | b->last = ngx_copy(b->last, (u_char *) NGX_HTTP_OAUTH_OPEN_INDEX, 291 | sizeof(NGX_HTTP_OAUTH_OPEN_INDEX) - 1); 292 | 293 | *b->last++ = CR; *b->last++ = LF; 294 | 295 | olcf = ngx_http_get_module_loc_conf(r, ngx_http_oauth_module); 296 | 297 | return olcf->create_request(r); 298 | } 299 | 300 | 301 | static ngx_int_t 302 | ngx_http_oauth_reinit_request(ngx_http_request_t *r) 303 | { 304 | return NGX_OK; 305 | } 306 | 307 | 308 | static ngx_int_t 309 | ngx_http_oauth_process_header(ngx_http_request_t *r) 310 | { 311 | u_char *p; 312 | ngx_http_upstream_t *u; 313 | ngx_http_oauth_ctx_t *ctx; 314 | ngx_http_oauth_loc_conf_t *olcf; 315 | 316 | u = r->upstream; 317 | 318 | again: 319 | 320 | for (p = u->buffer.pos; p < u->buffer.last; p++) { 321 | if (*p == LF) { 322 | goto found; 323 | } 324 | } 325 | 326 | u->buffer.pos = p; 327 | 328 | return NGX_AGAIN; 329 | 330 | found: 331 | 332 | if (*u->buffer.pos != '0') { 333 | return NGX_HTTP_UPSTREAM_INVALID_HEADER; 334 | } 335 | 336 | ctx = ngx_http_get_module_ctx(r, ngx_http_oauth_module); 337 | 338 | if (ctx->state == 0) { 339 | u->buffer.pos = p + 1; 340 | ctx->state = 1; 341 | goto again; 342 | } 343 | 344 | u->buffer.pos++; 345 | 346 | olcf = ngx_http_get_module_loc_conf(r, ngx_http_oauth_module); 347 | 348 | return olcf->process_header(r); 349 | } 350 | 351 | 352 | static ngx_int_t 353 | ngx_http_oauth_filter_init(void *data) 354 | { 355 | ngx_http_request_t *r = data; 356 | 357 | ngx_http_upstream_t *u; 358 | 359 | u = r->upstream; 360 | 361 | u->length = 0; 362 | 363 | return NGX_OK; 364 | } 365 | 366 | 367 | static ngx_int_t 368 | ngx_http_oauth_filter(void *data, ssize_t bytes) 369 | { 370 | return NGX_OK; 371 | } 372 | 373 | 374 | static void 375 | ngx_http_oauth_abort_request(ngx_http_request_t *r) 376 | { 377 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 378 | "abort http oauth request"); 379 | return; 380 | } 381 | 382 | 383 | static void 384 | ngx_http_oauth_finalize_request(ngx_http_request_t *r, ngx_int_t rc) 385 | { 386 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 387 | "finalize http oauth request"); 388 | 389 | return; 390 | } 391 | 392 | 393 | static ngx_int_t 394 | ngx_http_oauth_create_request_token_request(ngx_http_request_t *r) 395 | { 396 | size_t len; 397 | ngx_int_t rc; 398 | ngx_int_t key; 399 | ngx_str_t var; 400 | ngx_http_variable_value_t *vv; 401 | ngx_buf_t *b; 402 | ngx_chain_t *cl; 403 | ngx_http_oauth_ctx_t *ctx; 404 | ngx_http_oauth_loc_conf_t *olcf; 405 | 406 | olcf = ngx_http_get_module_loc_conf(r, ngx_http_oauth_module); 407 | 408 | ctx = ngx_http_get_module_ctx(r, ngx_http_oauth_module); 409 | 410 | ngx_str_set(&var, "arg_appid"); 411 | 412 | key = ngx_hash_key(var.data, var.len); 413 | 414 | vv = ngx_http_get_variable(r, &var, key); 415 | 416 | if (vv->not_found) { 417 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 418 | "request param appid not found"); 419 | return NGX_HTTP_NOT_ALLOWED; 420 | } 421 | 422 | if (ngx_strncmp(vv->data, olcf->appid.data, olcf->appid.len) != 0) { 423 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 424 | "appid not match %*s: %V", vv->len, vv->data, &olcf->appid); 425 | return NGX_HTTP_NOT_ALLOWED; 426 | } 427 | 428 | ngx_str_set(&var, "arg_secret"); 429 | 430 | key = ngx_hash_key(var.data, var.len); 431 | 432 | vv = ngx_http_get_variable(r, &var, key); 433 | 434 | if (vv->not_found) { 435 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 436 | "request param secret not found"); 437 | return NGX_HTTP_NOT_ALLOWED; 438 | } 439 | 440 | if (ngx_strncmp(vv->data, olcf->secret.data, olcf->secret.len) != 0) { 441 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 442 | "secret not match %*s: %V", vv->len, vv->data, &olcf->secret); 443 | return NGX_HTTP_NOT_ALLOWED; 444 | } 445 | 446 | rc = ngx_http_oauth_generate_data(r); 447 | 448 | if (rc == NGX_ERROR) { 449 | return NGX_ERROR; 450 | } 451 | 452 | len = sizeof("1\t+\t3\t") - 1 + ctx->access_token.len + 1 + ctx->expires_in.len + 1 + 453 | ctx->last_used_time.len + sizeof(CRLF) - 1; 454 | 455 | b = ngx_create_temp_buf(r->pool, len); 456 | if (b == NULL) { 457 | return NGX_ERROR; 458 | } 459 | 460 | cl = ngx_alloc_chain_link(r->pool); 461 | if (cl == NULL) { 462 | return NGX_ERROR; 463 | } 464 | 465 | cl->buf = b; 466 | cl->next = NULL; 467 | 468 | r->upstream->request_bufs->next = cl; 469 | 470 | b->last = ngx_copy(b->last, (u_char *) "1\t+\t3\t", sizeof("1\t+\t3\t") - 1); 471 | 472 | b->last = ngx_copy(b->last, ctx->access_token.data, ctx->access_token.len); 473 | 474 | *b->last++ = '\t'; 475 | 476 | b->last = ngx_copy(b->last, ctx->expires_in.data, ctx->expires_in.len); 477 | 478 | *b->last++ = '\t'; 479 | 480 | b->last = ngx_copy(b->last, ctx->last_used_time.data, ctx->last_used_time.len); 481 | 482 | *b->last++ = CR; *b->last++ = LF; 483 | 484 | return NGX_OK; 485 | } 486 | 487 | 488 | static ngx_int_t 489 | ngx_http_oauth_create_check_token_request(ngx_http_request_t *r) 490 | { 491 | size_t len; 492 | ngx_int_t key; 493 | ngx_str_t var; 494 | ngx_buf_t *b; 495 | ngx_chain_t *cl; 496 | ngx_http_variable_value_t *vv; 497 | 498 | ngx_str_set(&var, "arg_access_token"); 499 | 500 | key = ngx_hash_key(var.data, var.len); 501 | 502 | vv = ngx_http_get_variable(r, &var, key); 503 | 504 | if (vv->not_found) { 505 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 506 | "request param access_token not found"); 507 | return NGX_HTTP_NOT_FOUND; 508 | } 509 | 510 | len = sizeof("1\t=\t1\t") - 1 + vv->len - 1 + sizeof(CRLF) - 1; 511 | 512 | b = ngx_create_temp_buf(r->pool, len); 513 | if (b == NULL) { 514 | return NGX_ERROR; 515 | } 516 | 517 | cl = ngx_alloc_chain_link(r->pool); 518 | if (cl == NULL) { 519 | return NGX_ERROR; 520 | } 521 | 522 | cl->buf = b; 523 | cl->next = NULL; 524 | 525 | r->upstream->request_bufs->next = cl; 526 | 527 | b->last = ngx_copy(b->last, (u_char *) "1\t=\t1\t", sizeof("1\t=\t1\t") - 1); 528 | b->last = ngx_copy(b->last, vv->data, vv->len); 529 | 530 | *b->last++ = CR; *b->last++ = LF; 531 | 532 | return NGX_OK; 533 | } 534 | 535 | 536 | static ngx_int_t 537 | ngx_http_oauth_process_request_token_header(ngx_http_request_t *r) 538 | { 539 | size_t len; 540 | ngx_buf_t *b; 541 | ngx_chain_t *cl; 542 | ngx_http_upstream_t *u; 543 | ngx_http_oauth_ctx_t *ctx; 544 | 545 | u = r->upstream; 546 | 547 | ctx = ngx_http_get_module_ctx(r, ngx_http_oauth_module); 548 | 549 | len = sizeof("{\"access_token\":\"") - 1 + ctx->access_token.len + sizeof("\",\"expires_in\":") - 1 + ctx->expires_in.len + 1; 550 | 551 | b = ngx_create_temp_buf(r->pool, len); 552 | if (b == NULL) { 553 | return NGX_ERROR; 554 | } 555 | 556 | b->flush = 1; 557 | b->memory = 1; 558 | 559 | cl = ngx_alloc_chain_link(r->pool); 560 | if (cl == NULL) { 561 | return NGX_ERROR; 562 | } 563 | 564 | cl->buf = b; 565 | cl->next = NULL; 566 | 567 | b->last = ngx_copy(b->last, (u_char *) "{\"access_token\":\"", sizeof("{\"access_token\":\"") - 1); 568 | b->last = ngx_copy(b->last, ctx->access_token.data, ctx->access_token.len); 569 | b->last = ngx_copy(b->last, (u_char *) "\",\"expires_in\":", sizeof("\",\"expires_in\":") - 1); 570 | b->last = ngx_copy(b->last, ctx->expires_in.data, ctx->expires_in.len); 571 | *b->last++ = '}'; 572 | 573 | u->out_bufs = cl; 574 | 575 | r->headers_out.content_type_len = sizeof("text/html") - 1; 576 | r->headers_out.content_type.len = sizeof("text/html") - 1; 577 | r->headers_out.content_type.data = (u_char *) "text/html"; 578 | 579 | u->headers_in.status_n = 200; 580 | u->state->status = 200; 581 | 582 | u->headers_in.content_length_n = b->last - b->pos; 583 | 584 | return NGX_OK; 585 | } 586 | 587 | 588 | static ngx_int_t 589 | ngx_http_oauth_process_check_token_header(ngx_http_request_t *r) 590 | { 591 | size_t len; 592 | ngx_int_t rc; 593 | ngx_buf_t *b; 594 | time_t time_expires_in; 595 | time_t time_last_used_time; 596 | ngx_str_t expires_in; 597 | ngx_str_t last_used_time; 598 | ngx_chain_t *cl; 599 | ngx_http_upstream_t *u; 600 | ngx_http_oauth_ctx_t *ctx; 601 | 602 | u = r->upstream; 603 | 604 | ctx = ngx_http_get_module_ctx(r, ngx_http_oauth_module); 605 | 606 | rc = ngx_http_oauth_parse(r, ctx); 607 | 608 | if (rc != NGX_OK) { 609 | return rc; 610 | } 611 | 612 | expires_in.data = ctx->expires_in_begin; 613 | expires_in.len = ctx->expires_in_end - ctx->expires_in_begin; 614 | 615 | last_used_time.data = ctx->last_used_time_begin; 616 | last_used_time.len = ctx->last_used_time_end - ctx->last_used_time_begin; 617 | 618 | time_expires_in = ngx_parse_time(&expires_in, 1); 619 | if (time_expires_in == (time_t) NGX_ERROR) { 620 | return NGX_ERROR; 621 | } 622 | 623 | time_last_used_time = ngx_parse_time(&last_used_time, 1); 624 | if (time_last_used_time == (time_t) NGX_ERROR) { 625 | return NGX_ERROR; 626 | } 627 | 628 | if (time_last_used_time + time_expires_in < ngx_time()) { 629 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 630 | "access token has expired {%T}", time_expires_in); 631 | return NGX_ERROR; 632 | } 633 | 634 | len = sizeof(NGX_HTTP_OAUTH_RESPONSE_OK) - 1; 635 | 636 | b = ngx_create_temp_buf(r->pool, len); 637 | if (b == NULL) { 638 | return NGX_ERROR; 639 | } 640 | 641 | b->flush = 1; 642 | b->memory = 1; 643 | 644 | cl = ngx_alloc_chain_link(r->pool); 645 | if (cl == NULL) { 646 | return NGX_ERROR; 647 | } 648 | 649 | cl->buf = b; 650 | cl->next = NULL; 651 | 652 | b->last = ngx_copy(b->last, (u_char *) NGX_HTTP_OAUTH_RESPONSE_OK, 653 | sizeof(NGX_HTTP_OAUTH_RESPONSE_OK) - 1); 654 | 655 | u->out_bufs = cl; 656 | 657 | r->headers_out.content_type_len = sizeof("application/json") - 1; 658 | r->headers_out.content_type.len = sizeof("application/json") - 1; 659 | r->headers_out.content_type.data = (u_char *) "application/json"; 660 | 661 | u->headers_in.status_n = 200; 662 | u->state->status = 200; 663 | 664 | u->headers_in.content_length_n = sizeof(NGX_HTTP_OAUTH_RESPONSE_OK) - 1; 665 | 666 | return NGX_OK; 667 | } 668 | 669 | 670 | static ngx_int_t 671 | ngx_http_oauth_generate_data(ngx_http_request_t *r) 672 | { 673 | ngx_md5_t md5; 674 | u_char md5_buf[16]; 675 | ngx_str_t token; 676 | ngx_http_oauth_ctx_t *ctx; 677 | ngx_http_oauth_loc_conf_t *olcf; 678 | 679 | olcf = ngx_http_get_module_loc_conf(r, ngx_http_oauth_module); 680 | 681 | ctx = ngx_http_get_module_ctx(r, ngx_http_oauth_module); 682 | 683 | token.data = ngx_pnalloc(r->pool, sizeof("18446744073709551616_") - 1 684 | + NGX_TIME_T_LEN); 685 | 686 | if (token.data == NULL) { 687 | return NGX_ERROR; 688 | } 689 | 690 | token.len = ngx_sprintf(token.data, "%ul_%T", ngx_random(), ngx_time()) 691 | - token.data; 692 | 693 | ctx->access_token.data = ngx_palloc(r->pool, 32); 694 | if (ctx->access_token.data == NULL) { 695 | return NGX_ERROR; 696 | } 697 | 698 | ngx_md5_init(&md5); 699 | ngx_md5_update(&md5, token.data, token.len); 700 | ngx_md5_final(md5_buf, &md5); 701 | 702 | ngx_hex_dump(ctx->access_token.data, md5_buf, sizeof(md5_buf)); 703 | 704 | ctx->access_token.len = 32; 705 | 706 | ctx->expires_in.data = ngx_pnalloc(r->pool, NGX_TIME_T_LEN); 707 | if (ctx->expires_in.data == NULL) { 708 | return NGX_ERROR; 709 | } 710 | 711 | ctx->expires_in.len = ngx_sprintf(ctx->expires_in.data, "%T", olcf->expires_in) 712 | - ctx->expires_in.data; 713 | 714 | ctx->last_used_time.data = ngx_pnalloc(r->pool, NGX_TIME_T_LEN); 715 | 716 | if (ctx->last_used_time.data == NULL) { 717 | return NGX_ERROR; 718 | } 719 | 720 | ctx->last_used_time.len = ngx_sprintf(ctx->last_used_time.data, "%T", ngx_time()) 721 | - ctx->last_used_time.data; 722 | 723 | return NGX_OK; 724 | } 725 | 726 | 727 | static ngx_int_t 728 | ngx_http_oauth_parse(ngx_http_request_t *r, ngx_http_oauth_ctx_t *ctx) 729 | { 730 | u_char c, ch, *p; 731 | ngx_buf_t *b; 732 | ngx_http_upstream_t *u; 733 | 734 | enum { 735 | sw_start = 0, 736 | sw_before_num, 737 | sw_after_num, 738 | sw_before_column1, 739 | sw_column1, 740 | sw_before_column2, 741 | sw_column2, 742 | sw_before_column3, 743 | sw_column3, 744 | sw_almost_done 745 | } state; 746 | 747 | u = r->upstream; 748 | 749 | b = &u->buffer; 750 | 751 | state = ctx->parse_state; 752 | 753 | for (p = b->pos; p < b->last; p++) { 754 | ch = *p; 755 | 756 | switch (state) { 757 | 758 | case sw_start: 759 | 760 | if (ch == '\t') { 761 | state = sw_before_num; 762 | break; 763 | } 764 | 765 | return NGX_HTTP_UPSTREAM_INVALID_HEADER; 766 | 767 | case sw_before_num: 768 | 769 | c = (u_char) (ch | 0x20); 770 | if (c == '3') { 771 | state = sw_after_num; 772 | break; 773 | } 774 | 775 | return NGX_HTTP_UPSTREAM_INVALID_HEADER; 776 | 777 | case sw_after_num: 778 | 779 | if (ch == '\t') { 780 | state = sw_before_column1; 781 | break; 782 | } 783 | 784 | return NGX_HTTP_UPSTREAM_INVALID_HEADER; 785 | 786 | case sw_before_column1: 787 | ctx->access_token_begin = p; 788 | state = sw_column1; 789 | break; 790 | 791 | case sw_column1: 792 | 793 | switch (ch) { 794 | case '\t': 795 | ctx->access_token_end = p; 796 | state = sw_before_column2; 797 | break; 798 | default: 799 | break; 800 | } 801 | break; 802 | 803 | case sw_before_column2: 804 | ctx->expires_in_begin = p; 805 | state = sw_column2; 806 | break; 807 | 808 | case sw_column2: 809 | 810 | switch (ch) { 811 | case '\t': 812 | ctx->expires_in_end = p; 813 | state = sw_before_column3; 814 | break; 815 | default: 816 | break; 817 | } 818 | break; 819 | 820 | case sw_before_column3: 821 | ctx->last_used_time_begin = p; 822 | state = sw_column3; 823 | break; 824 | 825 | case sw_column3: 826 | 827 | switch (ch) { 828 | case CR: 829 | ctx->last_used_time_end = p; 830 | state = sw_almost_done; 831 | break; 832 | case LF: 833 | ctx->last_used_time_end = p; 834 | goto done; 835 | default: 836 | break; 837 | } 838 | break; 839 | 840 | case sw_almost_done: 841 | switch (ch) { 842 | case LF: 843 | goto done; 844 | default: 845 | return NGX_HTTP_UPSTREAM_INVALID_HEADER; 846 | } 847 | } 848 | } 849 | 850 | b->pos = p; 851 | ctx->parse_state = state; 852 | 853 | return NGX_HTTP_UPSTREAM_INVALID_HEADER; 854 | 855 | done: 856 | 857 | b->pos = p + 1; 858 | 859 | ctx->parse_state = sw_start; 860 | 861 | return NGX_OK; 862 | } 863 | 864 | 865 | static void * 866 | ngx_http_oauth_create_loc_conf(ngx_conf_t *cf) 867 | { 868 | ngx_http_oauth_loc_conf_t *conf; 869 | 870 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_oauth_loc_conf_t)); 871 | if (conf == NULL) { 872 | return NULL; 873 | } 874 | 875 | conf->upstream.local = NGX_CONF_UNSET_PTR; 876 | conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; 877 | conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; 878 | conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; 879 | 880 | conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; 881 | 882 | conf->expires_in = NGX_CONF_UNSET; 883 | 884 | return conf; 885 | } 886 | 887 | 888 | static char * 889 | ngx_http_oauth_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) 890 | { 891 | ngx_http_oauth_loc_conf_t *prev = parent; 892 | ngx_http_oauth_loc_conf_t *conf = child; 893 | 894 | ngx_conf_merge_ptr_value(conf->upstream.local, 895 | prev->upstream.local, NULL); 896 | 897 | ngx_conf_merge_msec_value(conf->upstream.connect_timeout, 898 | prev->upstream.connect_timeout, 60000); 899 | 900 | ngx_conf_merge_msec_value(conf->upstream.send_timeout, 901 | prev->upstream.send_timeout, 60000); 902 | 903 | ngx_conf_merge_msec_value(conf->upstream.read_timeout, 904 | prev->upstream.read_timeout, 60000); 905 | 906 | ngx_conf_merge_size_value(conf->upstream.buffer_size, 907 | prev->upstream.buffer_size, 908 | (size_t) ngx_pagesize); 909 | 910 | if (conf->upstream.upstream == NULL) { 911 | conf->upstream.upstream = prev->upstream.upstream; 912 | } 913 | 914 | ngx_conf_merge_str_value(conf->db, prev->db, ""); 915 | ngx_conf_merge_str_value(conf->table, prev->table, ""); 916 | 917 | ngx_conf_merge_sec_value(conf->expires_in, prev->expires_in, 7200); 918 | 919 | return NGX_CONF_OK; 920 | } 921 | 922 | 923 | static char * 924 | ngx_http_oauth_request_token(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 925 | { 926 | ngx_http_oauth_loc_conf_t *olcf = conf; 927 | 928 | if (ngx_http_oauth_pass(cf, olcf) == NGX_CONF_ERROR) { 929 | return NGX_CONF_ERROR; 930 | } 931 | 932 | olcf->create_request = ngx_http_oauth_create_request_token_request; 933 | olcf->process_header = ngx_http_oauth_process_request_token_header; 934 | 935 | return NGX_CONF_OK; 936 | } 937 | 938 | 939 | static char * 940 | ngx_http_oauth_check_token(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 941 | { 942 | ngx_http_oauth_loc_conf_t *olcf = conf; 943 | 944 | if (ngx_http_oauth_pass(cf, olcf) == NGX_CONF_ERROR) { 945 | return NGX_CONF_ERROR; 946 | } 947 | 948 | olcf->create_request = ngx_http_oauth_create_check_token_request; 949 | olcf->process_header = ngx_http_oauth_process_check_token_header; 950 | 951 | return NGX_CONF_OK; 952 | } 953 | 954 | 955 | static char * 956 | ngx_http_oauth_pass(ngx_conf_t *cf, ngx_http_oauth_loc_conf_t *olcf) 957 | { 958 | ngx_str_t *value; 959 | ngx_url_t u; 960 | ngx_http_core_loc_conf_t *clcf; 961 | 962 | if (olcf->upstream.upstream) { 963 | return "is duplicate"; 964 | } 965 | 966 | value = cf->args->elts; 967 | 968 | ngx_memzero(&u, sizeof(ngx_url_t)); 969 | 970 | u.url = value[1]; 971 | u.no_resolve = 1; 972 | 973 | olcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0); 974 | if (olcf->upstream.upstream == NULL) { 975 | return NGX_CONF_ERROR; 976 | } 977 | 978 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 979 | 980 | clcf->handler = ngx_http_oauth_handler; 981 | 982 | return NGX_CONF_OK; 983 | } 984 | --------------------------------------------------------------------------------