hello,我是卷卷毛,我又来啦
咱们书接上回,上一节我们讨论了一种基于token验证方式的登录方案,文章在这里:
上节的内容,简单些说,就是介绍了一种实现用户登录的方式。
服务端在校验用户的账号密码信息无误后,为用户生成一串token作为口令返回给用户。之后,按照约定,用户在访问后端时将token添加在请求头中,发送给后端。后端根据头部中的token信息校验用户的登录状况。
那么这一节,承接上回,我们要解决这一登录方案的前后端交互问题,焦点在于token的获取,存储,传递和移除,别看这个问题简单,实现起来却是困难重重,博主就在这里疯狂蹚雷(爆哭),于是才有了这篇博客,也是帮看到这篇博客的小伙伴避避雷。
(碎碎念:虽说token登录的方式可以避开跨域请求中Cookie传递的若干问题,但是在实践中却总是无法绕开这个话题,也许跨域问题是前后端分离开发必攻下的一块高地吧)
对于这个问题,有的小伙伴一听:
哈?这么简单,在请求中添加一个请求头不就好了?
不过看起来确实是很简单,但是别着急嗷,不妨先来回顾一下我们后台的流程:
上一篇文章中,编写的后台有三个接口以及一个拦截器:
-
/user/login
用户登录接口,访问的时候需要传递username
和password
,只认识账号123456789
,密码123456
。登录成功会返回用户的token -
/user/logout
用户登出接口,访问的时候回检测用户是否处于登录状态,如果用户处于登录状态则将用户登出。 -
/user/loginStatus
用户登录状态,访问会返回此时用户的登录状态 -
AuthorizationFilter
登录拦截器,会检测请求头Authorization
字段中的token以判断用户的登录状态。
复习完后,让我们写个简答的前端,试着使用123456789
,123456
登录获取token:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>token传递</title>
</head>
<body>
<button id="login">点击登录</button>
<button id="logout">点击登出</button>
<button id="login-status">登录状态</button>
</body>
</html>
接着给每个按钮编写对应的点击事件,访问三个接口。这三个接口就包含着对token的重要基本操作
- 获取
- 存储
- 携带
- 移除
用户登录及token存储
在发送token之前我们要先拿到token呐,所以先为登录按钮编写点击事件,像/user/login
发送一个登录请求:
$('#login').click(()=>{
$.ajax({
url:'http://localhost/user/login',
data:{
username:'123456789',
password:'123456'
},
type:'POST',
success:(res)=>{
alert(res);
}
})
})
点击发送,可以看到后台的提示信息:
但是前台并没有弹出窗口,感觉这个请求不太对劲,打开控制台一看:
第一个跨域问题:访问控制源
原来是遇到了跨域的问题,提示我们需要在response
中设置头Control-Allow-Origin
。他表示跨域请求允许的访问源。
看到这个问题,不要惊慌,应为
这个问题经常是出现在小伙伴们前后端分离开发的第一只拦路虎。
这个看似前端的问题,其实是后端的,需要在后端给相应头中加上若干跨域相关字段
由于后面我们还要频繁的设置响应头的信息。我们不妨在后端设置一个跨域拦截器CROSFilter
,专门负责对跨域请求进行处理:
@Order(1)//拦截器排序,跨域拦截最先进行拦截
@WebFilter(filterName="CROSFilter",urlPatterns= {
"*.action","*"})
public class CROSFilter implements Filter{
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse rep= (HttpServletResponse)response;
System.out.println("跨域拦截器拦截到请求:" + req.getRequestURI());
//设置允许访问域,这里直接取访问域,表示允许来自这个域的请求
rep.setHeader("Access-Control-Allow-Origin", req.getHeader("origin"));
//执行拦截链中的下一环
chain.