1.Nginx的前置准备
要通过Nginx搭配spring security进行鉴权,Nginx需要使用下面这个模块 --with-http_auth_request_module
window环境版本的nginx默认是开启的,直接可以使用,linux系统的需要手动开启
- linux使用
--with-http_auth_request_module
模块
先查看当前系统下的nginx版本,只有安装的有模块了才会看到除了版本之外的信息。
[root ~]# nginx -V
nginx version: nginx/1.21.3
built by gcc 8.5.0 20210514 (Red Hat 8.5.0-4) (GCC)
built with OpenSSL 1.1.1k FIPS 25 Mar 2021
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_auth_request_module
上面命令即可查看nginx的版本,以及开启了那些模块,如果执行上述命令 ‘提示未找到命令’
则需要配置path
即:
[root ~]# vim /etc/profile
#对profiel文件最下面 添加下面代码
#此处是你nginx安装路径,根据自己实际情况修改
PATH=$PATH:/usr/local/nginx/sbin
然后即可使用 nginx -V 查看信息了
- 如果安装过
--with-http_auth_request_module
模块 则忽略此处,如果没有则按下述操作
进入nginx解压目录下,查看是否有congiure
这个文件,如果没有则需要去官方网址:http://nginx.org/en/download.html下载对应的版本,进行解压,并把解压下的congiure
文件,复制到nginx目录下,
执行下面命令:
说明:nginx的解压地址和安装地址可能不同,解压地址下包含configure不包含sbin, nginx的安装地址下没有configure,有sbin。
#说明 profix= 自己nginx安装地址 后面--with-xx的根据通过命令 nginx -V 查询到的都需要添加上,此处只多添加一个--with-http_auth_request_module 这个模块,有需要其他模块的 自行查找添加。
[root nginx]# ./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_auth_request_module
#然后执行
[root nginx]# make
[root nginx]# make install
#在执行nginx -V即可查看到 安装的模块
[root nginx]# nginx -V
- Nginx的配置
#此处拦截 根据自己需求进行拦截
location /static/profile {
auth_request /check;
error_page 401 = /auth_page;
proxy_pass http://localhost:8080/profile;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
#认证路径
location = /check {
#表示该路径仅仅为nginx内部访问,一旦出了这个配置文件,则失效
internal;
#自己系统的认证路径
proxy_pass http://localhost:8080/check;
error_page 401 402 403 404 /auth_page;
}
#认证失败后的处理
location = /auth_page{
#强制浏览器不使用缓存,防止缓存带来的还能访问系统
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate";
#如果认证失败,跳转到自己系统的登录页面
return https://xxx/login;
}
- 后台代码编写请求接口,需与上面Nginx配置的
auth_request /check;
保持一致
@GetMapping("/check")
public void nginxCheck()
{
#此处我只是利用security校验功能,没写具体东西,只打印一句话 说明访问静态资源时,也通过了鉴权才访问的
System.out.println("nginx 校验");
}
- 修改鉴权部分代码
#说明: 避免验权从header里面去取Authorization,有些时候可能header里面没有携带认证信息,自定义一个存放token保存客户的登录信息放在cookie里面,用于静态资源访问
#1.客户登录之后,在最后设置一个token存放cookie里面
//设置cookie
Cookie cookie = new Cookie("check", token);
cookie.setPath("/");
cookie.setHttpOnly(true);
cookie.setSecure(true);
response.addCookie(cookie);
#2.验权,如果JWT获取不到token,再去取一下自己设置的check下的token
private String getToken(HttpServletRequest request)
{
String token = request.getHeader(token);
if (Strings.isBlank(token)) {
Cookie[] cookies = request.getCookies();
if (cookies != null && cookies.length > 0) {
for (Cookie cookie : cookies) {
if ("check".equals(cookie.getName())) {
token = cookie.getValue();
}
}
}
}
if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX))
{
token = token.replace(Constants.TOKEN_PREFIX, "");
}
return token;
}
6.此时重启项目,未登录之前,直接访问静态资源会跳转登录页面,如果登录之后,会进行鉴权获取静态资源(可在鉴权接口里面打印日志进行查看)
一些遇到的问题:
- 首先检查一下自己的nginx是否重启成功,遇到过
./nginx -s reload
执行后,nginx一些修改没生效问题。 - 根据自己服务器是内网还是外网,cookie来设置 cookie.setSecure(true); 因为有些浏览器会在设置cookie是提示
尝试通过Set-Cookie标头设置Cookie时被阻止,因为它具有“Secure“属性,但未通过安全连接发送
,所以导致再次请求的时候不携带cookie,从而导致认证不通过。