如今不少项目早就采用先后端分离的方式开发和部署了。前端代码部署在nginx服务器上,由nginx直接对外提供静态文件的服务,后端接口则由nginx作反向代理。html
这原本是极为合理的部署方式,但对于一些须要登陆才能进行访问的系统,负责安全的同事就会提出以下的疑虑:前端
index.html容许匿名访问,别有用心之人岂不是能够根据index里的<script>标签,拿到你全部的前端代码了?java
看来要解决这个问题。nginx
为了保护前端首页代码,一次请求的流程应该是下面这样:后端
用户发起首页的请求,服务端发现用户没有登陆,跳转到登陆页;
用户发起首页的请求,服务端发现用户已经登陆了,正常输出首页的内容。api
注意,这里是服务端判断,而不是客户端判断。tomcat
判断有没有登陆,毫无疑问是是咱们的java后端才能作到的事情,可是首页是html文件,在nginx下面,用户请求它的时候还没到后端这里呢,怎么判断?安全
固然,你能够把前端文件移到后端tomcat下,由tomcat提供服务,但这样又走回老路了,这不是一个好方法,不推荐。服务器
其实,在不改变部署架构的前提下,咱们简单的经过nginx的配置和后端接口的配合,就能够达到目的。cookie
简单来讲,利用nginx的rewrite + error_page指令来实现。
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); }