前后端分离部署时如何保护前端代码不被匿名访问

    

前后端分离部署时如何保护前端代码不被匿名访问

背景
现在很多项目早就采用前后端分离的方式开发和部署了。前端代码部署在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);
}

所有原创文章采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。
您可以自由的转载和修改,但请务必注明文章来源并且不可用于商业目的。
本站部分内容收集于互联网,如果有侵权内容、不妥之处,请联系我们删除。敬请谅解!

  Previous post Vue封装时间格式化插件
Next post   Nginx限流

添加新评论

  关于博主

QQ:1960727927
E-Mail:ceet@vip.qq.com
个人主页:https://aiylqy.com
个性签名:毁掉一个人最好的方式就是放纵他的缺点。

  近期评论

青春就是用来追忆的,当你怀揣着它时,它一文不值,只有将它耗尽后,再回过头看,一切才有了意义,爱过我们的人和伤害过我们的人,都是我们青春存在的意义。

既然活着来到这个世界,就没有打算活着回去。所以,在这有限的时间里,我们应该珍惜生命,珍惜机会,更要珍惜那得之不易的时间。因那滴答做响的时间脚步,一旦走过,再不回头。

青春是一个充满魁力,充满诱惑的时代。好动是青春,好奇是青春,好玩是青春。玩世不恭更是青春,我们的一切切都是青春。

要先打败任何事情得先学会打败自己。

我会把每一次改变当做成长,哪怕是痛也值得。