假设我们不适用前后端分离,那么登录成功之后,我们会把用户的信息存储到session中,之后的每一次请求,都会带着cookies中的session_id,服务端会自行验证此用户是否登录及登录是否失效,那么问题来了,我们使用了前后端分离,那么就意味着没有了session,每一次的请求都是无状态的,作为后端我们不知道是登录用户请求的还是非登录用户请求的,所以,为了解决这个问题,我们有这么几种方式
授权的方式,可以参考OAUTH
用户登录之后,后端返给前端一个有过期时间的token,每次前端请求的时候就携带这个token
网关鉴权,就是我现在想说的
比较3种方法,前两种是比较常见的,但是都需要在项目的代码中做验证,对于高并发来说,性能还是有一些影响的,如果你使用的语言性能较差的话,每次请求都要在代码中验证token,验证redis等
第三种方法,适合高性能api,现在就详细说下咱们如何实现的
1.使用openResty,天然支持lua脚本
2.登录的时候,如果登录成功向redis中写入用户信息及失效时间
3.要求前端调用接口的时候在header中加入鉴权数据,比如用户id,签名等信息
4.使用lua去读取header内的内容,比如读取到了用户的id,然后根据自己制定的规则去验证签名,去redis中查询数据来实现鉴权
这块比较涉密,所以我拆分成几个小部分来大体说下思路
lua获取header中的信息
local userId = ngx.req.get_headers()["userid"] if userId == nil or userId == "" then ngx.say("{\"code\": 401, \"msg\":\"userid获取失败\" }") return end
2. lua连接redis并查询数据
local redis = require "resty.redis" local red = redis:new() red:set_timeout(1000) local ok, err = red:connect('127.0.0.1', '6379') if not ok then ngx.log(ngx.ERR, "redis 连接失败") ngx.say('{"code":500, "msg":"服务器错误(red err:1)"}') return end local userInfo, err = red:hmget("键值/",'字段名')
3. 然后看下nginx的配置,通过access_by_lua_file来加载lua鉴权脚本,这样每次请求都会先去执行lua,然后在去执行我们的代码
server { charset utf-8; client_max_body_size 128M; listen 80; root /home/www/root/lvs; index index.php; location / { access_by_lua_file /home/openresty/nginx/conf/lua_script/on_access.lua; try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { include fastcgi_params; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; include fastcgi_params; } location ~ /\.(ht|svn|git) { deny all; } }
看下鉴权失败的情况,我传递了错误的鉴权数据
传递正确的数据
鉴权数据失效后,可以要求用户重新登录,然后再次将信息写入redis