背景:
最近项目的开发架构改为前后端分离模式;
前端采用vue框架npm编译后在tomcat独立部署,前后端完全通过http请求接口的方式进行交互,页面控制权交给前端,后端只提供页面所需数据而已!
由此带来的主要问题就是登录系统如何设计?以前项目都是通过Shiro框架内部控制cookie、session、登陆状态、页面权限等一系列资源,现在前端页面脱离后端项目后,我们要做出哪些改变呢?


一、先看看之前我们如何做登录

之前前后端未分离时,前端的html页面等静态资源都在我们后台项目的webapp目录下:
这里写图片描述
通过shiro框架的过滤链对所有url访问进行拦截和权限控制:
这里写图片描述
在controller层中进行登录相关操作和判断,再决定页面如何跳转:
这里写图片描述
在shiro中,也是通过设置浏览器的cookie(sessionid),映射服务器的用户session来判断用户登录状况:每次点击登录按钮时后台的response将sessionid的cookie添加到浏览器,后面所有访问请求都带着该cookie,shiro的相关方法就会获取cookie匹配session确定用户登录信息。


前后端分离后存在哪些问题呢?


二、跨域问题

首先,我们要明确的是,分离后就是两个系统了,都有各自的ip端口各自的域,由此将会带来各种跨域问题

根据同源策略,跨域的 “域” 指的是 URL,包括协议、域名、端口;
我们可以通过观察浏览器的cookie发现,cookie是不区分端口的,各域名或ip都是在浏览器共享cookie的:
这里写图片描述
那么同一ip不同端口的前端系统访问后台系统,能像之前一样完美setCookie、getCookie,在http请求中都携带cookie么?当然没这么容易呢!
这里面就存在跨域问题,业内往往通过 跨域资源共享 CORS方案来解决跨域问题,这需要前后端一起配合解决,在此贴出我们的代码方案:

1. 后端添加拦截器对http请求设置header
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Author: yuanj
 * @Date: 2018/5/31 15:41
 */
@Component
public class MoerInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {

        response.setHeader("Access-Control-Allow-Origin",request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Methods","POST,GET,OPTIONS,DELETE,PUT");
        response.setHeader("Access-Control-Max-Age","3600");
        response.setHeader("Access-Control-Allow-Headers","X-Requested-With,Authorization,Content-Type,token");
        response.setHeader("Access-Control-Allow-Credentials","true");
        response.setHeader("Content-Type","text/html;charset=UTF-8");

        return true;
    }
}

Access-Control-Allow-Credentials
该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。

需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie!

2.前端ajax或axios访问时必须添加 withCredentials 属性

CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials: true,另一方面,开发者必须在AJAX请求中打开 withCredentials 属性。

this.$axios.default.withCredentials = true

否则,即使服务器同意发送Cookie,浏览器也不会发送。或者,服务器要求设置Cookie,浏览器也不会处理。


三、页面控制问题

之前是后台项目内部拦截请求,控制页面跳转,现在前端分离后就不能在后端控制了。我们只能通过接口的方式给前端提供登录相关数据,前端根据我们返回的状态码等信息自己去控制页面跳转!
这里写图片描述


四、登录方式设计

一般登录系统设计有两种方式:JWT基于session的登录认证

JWT方式是把用户所有信息加密形成一个token字符串,每次前端请求后端时header都携带该字符串,后端根据这个token解密后获取用户登录相关信息;

基于session的登录认证则比较传统,服务器端保存session信息,根据前端cookie中的sessionid取得相应session进行解析获取用户相关信息,由于我们之前shiro就是用这种方式设计登录,所以前后端分离时依旧可以这样处理!

此处存在一个问题:前端如何判断登录状态?
一般来说,为了安全起见登录状态必须由后端判断,完全交给前端以本地存储的方式判断是否登录并不科学。只在后端接口通过拦截器判断用户登录状态也只能对访问的接口进行控制,无法对前端页面进行控制,这样也不科学。

所以我目前的方案是:前端在页面路由跳转时,首先访问后端的一个判断登录状态的接口,处于登录状态才继续跳转,不然返回登陆页面!其次,也在后台项目里配置拦截器去判断登录状态,确定该用户处于已登录时才去查询接口!这样就对页面和接口都进行了控制了。


后续会关于单点登录、redis存储session、nginx配置再做更新~

Logo

前往低代码交流专区

更多推荐