共计 2134 个字符,预计需要花费 6 分钟才能阅读完成。
背景
现在很多项目早就采用前后端分离的方式开发和部署了。前端代码部署在 nginx 服务器上,由 nginx 直接对外提供静态文件的服务,后端接口则由 nginx 做反向代理。
这本来是极为合理的部署方式,但对于一些需要登录才能进行访问的系统,负责安全的同事就会提出如下的疑虑:
index.html 允许匿名访问,别有用心之人岂不是可以根据 index 里的 <script> 标签,拿到你所有的前端代码了?
看来要解决这个问题。
思路
为了保护前端首页代码,一次请求的流程应该是下面这样:
用户发起首页的请求,服务端发现用户没有登录,跳转到登录页;
用户发起首页的请求,服务端发现用户已经登录了,正常输出首页的内容。
注意,这里是服务端判断,而不是客户端判断。
判断有没有登录,毫无疑问是是我们的 java 后端才能做到的事情,但是首页是 html 文件,在 nginx 下面,用户请求它的时候还没到后端这里呢,怎么判断?
当然,你可以把前端文件移到后端 tomcat 下,由 tomcat 提供服务,但这样又走回老路了,这不是一个好方法,不推荐。
其实,在不改变部署架构的前提下,我们简单的通过 nginx 的配置和后端接口的配合,就可以达到目的。
简单来说,利用 nginx 的 rewrite + error_page 指令来实现。
- 首先,利用 nginx 的 rewrite 指令,把对 index 的请求,rewrite 到后端某个接口上
- 后端这个接口里判断当前用户是否已经登录,如果没有登录,返回 302 跳转,跳转到授权页去登录
- 如果后端接口判断当前用户已经登录,则返回一个错误码给 nginx(例如 404),nginx 利用 error_page,指定 404 时,输出 index.html 的文件内容。
nginx 示例配置如下:
server {
listen 80;
server_name www.abc.com;
recursive_error_pages on; #这个选项要开启
location / {root /path/to/front-end;}
location /api #交由 tomcat 处理
{
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Cookie $http_cookie;
proxy_pass http://localhost:9000;
}
location ~* ^(/|(/index\.html))$ {
#未登录的情况下,不允许访问首页,注意这里 rewrite 到一个 location,而不是直接 proxy_pass 到后端接口。因为我要在 @fallback 里利用 queryString
rewrite ^/(.*) /abcdefg?res=$request_uri;
}
#
location /abcdefg {
proxy_pass http://localhost:9000/api/home/check-user?res=$request_uri;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_intercept_errors on;
error_page 404 = @fallback;
}
location @fallback {if ($query_string ~* ^res=([^&]*)) {
set $path $1;
rewrite ^ /local/scripts$path;
}
}
location /local/scripts/ {
internal; #nginx 内部才有效的 location,外部无法通过 /local/scripts/ 这个路径访问
alias /path/to/front-end/; #注意,最后有个 / 符号
error_page 404 =200 /local/scripts/index.html;
}
}
后端 check-user 接口示例如下:
@GetMapping("check-user")
public void checkUser(String res, HttpSession session, HttpServletRequest request, HttpServletResponse response) throws IOException {if(session.getAttribute("User") == null){response.sendRedirect("login?returnUrl=" + URLEncoder.encode(res, "UTF-8"));
return;
}
response.setStatus(HttpStatus.SC_NOT_FOUND);
}
正文完