Nginx使用OpenResty+Lua+Redis进行token鉴权 原创

背景介绍

公司有很多项目通过sphinx生成了Html文档,通过nginx转发,前进前端界面展示,方便员工查阅和使用。
出于安全考虑,现需要添加一个登陆界面,接入公司的统一认证系统,进行账号校验

制定方案

  • 通过Oauth2连接公司统一认证系统(spring Oauth2
  • 前端调用Oauth2获取Token
  • Nginx通过token校验实现鉴权功能

此处主要讲Nginx使用Lua脚本连接Redis校验Token是否存在。

Token不存在
Token存在
输入账号密码
Token正确
Token错误
用户访问
nginx判断是否存在Token
跳转到Loigin界面
Nginx校验Token是否正确
登陆成功跳转到首页
登陆成功跳转到首页

使用OpenResty

Nginx 官方是没有 Lua 模块的,所以手动引入 OpenResty 开发的 ngx_http_lua_module不如直接使用 openresty
openresty是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

Lua语言

Lua 是一种轻量小巧的脚本语言,用标准 C 语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。基础语法可以参考:https://www.runoob.com/lua/lua-tutorial.html

代码逻辑处理

获取Token

开始代码编写,第一步是从请求中获取鉴权参数,如果没获取到,跳转到登录页面。

-- lua 获取Nignx变量为:ngx.var
-- 从cookie中获取token值(key为token)
local token = ngx.var.cookie_token
--判断token是否为空,为空跳转
if not token then
    ngx.redirect("http://test.example.com/login", 302)
--判断token存在,则根据redis存储格式拼写Token
else
   token = "auth:" .. ngx.var.cookie_token
end

或者从URL中获取token。

主要依据为前端传送Token存放的位置

local token = ngx.var.arg_token

发起鉴权

此处仅连接redis,检查是否存在该token,未做进一步权限鉴别。

local function close_redis(red)
    if not red then
        return
    end
    local pool_max_idle_time = 10000 --毫秒  
    local pool_size = 100 --连接池大小  
    local ok, err = red:set_keepalive(pool_max_idle_time, pool_size) 
    if not ok then
        ngx.say("close redis error : ",err);
    end
end

-- 连接redis
local redis = require "resty.redis";
local red = redis:new();
red:set_timeout(2000)

local ok,err = red:connect("127.0.0.1", 6379)
if not ok then
  ngx.say("failed to connect: ", err)
end

-- 请注意这里 auth 的调用过程 这是redis设置密码的
local res, err = red:auth("password")
if not res then
  ngx.say("failed to authenticate: ", err)
end

-- redis中若 key 存在返回 1 ,否则返回 0 。
local resp, err = red:exists(token) 
if not resp then  
    ngx.say("get msg error : ", err)  
    return close_redis(red)  
end  
if resp == ngx.null then  
    resp = ''  
end  
if resp == 0 then
--   ngx.exit(ngx.HTTP_FORBIDDEN)
    ngx.redirect("http://test.example.com/login", 302)
end
close_redis(red)

Nginx配置及完整代码

server {
    listen 80;
    server_name test.example.com;


    charset utf-8;
    autoindex on;
    autoindex_exact_size on;
    autoindex_localtime on;

    location / {
         lua_code_cache on;
         rewrite_by_lua_file /usr/local/openresty/nginx/conf/conf.d/redis.lua;
         error_log /usr/local/openresty/nginx/logs/error.log;
         root /data/;
         index index.html;
     }

    location /login {
        alias /data/login;
        index index.html;
}
}
  • /usr/local/openresty/nginx/conf/conf.d/redis.lua
-- 从cookie中获取token值key为token)
local token = ngx.var.cookie_token
--判断token是否为空,为空跳转
if not token then
    ngx.redirect("http://test.example.com/login", 302)
--判断token存在,则根据redis存储格式拼写Token
else
   token = "auth:" .. ngx.var.cookie_token
end

local function close_redis(red)
    if not red then
        return
    end
    local pool_max_idle_time = 10000 --毫秒  
    local pool_size = 100 --连接池大小  
    local ok, err = red:set_keepalive(pool_max_idle_time, pool_size) 
    if not ok then
        ngx.say("close redis error : ",err);
    end
end

-- 连接redis
local redis = require "resty.redis";
local red = redis:new();
red:set_timeout(2000)

local ok,err = red:connect("127.0.0.1", 6379)
if not ok then
  ngx.say("failed to connect: ", err)
end

-- 请注意这里 auth 的调用过程 这是redis设置密码的
local res, err = red:auth("password")
if not res then
  ngx.say("failed to authenticate: ", err)
end

-- redis中若 key 存在返回 1 ,否则返回 0 。
local resp, err = red:exists(token) 
if not resp then  
    ngx.say("get msg error : ", err)  
    return close_redis(red)  
end  
if resp == ngx.null then  
    resp = ''  
end  
if resp == 0 then
--   ngx.exit(ngx.HTTP_FORBIDDEN)
    ngx.redirect("http://test.example.com/login", 302)
end
close_redis(red)
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值