先后端分离以后添加验证码

转载自:http://www.cnblogs.com/liminjun88/p/6556493.html#commentform

1.背景介绍

团队开发的项目,前端基于Bootstrap+AngularJS,后端Spring MVC以RESTful接口给前端调用。开发和部署都是先后端分离。项目简单部署图以下,由于后台同时采用微服务的方式,因此后台不止3个,画图示意。终极方案是采用Docker,在前端和后台调用中间添加一层:API Gateway。javascript

部署图

由于考虑到和其余系统集成的可能性,因此在登陆这一块使用了Token来作登陆,认证服务器负责生成Token和验证Token。由于客户须要提升系统的安全性,须要在登陆页添加一个验证码。可是由于项目是基于先后端分离的,因此添加验证码的功能仍是有一些不同。html

登陆页

2.Session解决方案

有经验的开发者第一反应就是以前验证码怎么添加的,如今在这里也是一样的道理,为何不同呢?由于先后端分离,系统登陆使用的是Token,后台再也不设置Session了。后台必须保证当前用户输入的验证码是用户开始请求页面时候的验证码,必须保证验证码的惟一性。举个例子:前端

A用户看到的验证码是:ABC;B用户看到的验证码是:DEF。后台存储了ABC和DEF这2个验证码,若是不限定A用户输入的验证码是ABC,那么当A用户碰巧输入DEF,而后用户名和密码也是正确的话,A用户也是能够登陆系统的。java

在早期可使用Session系统中,后台返回验证码信息同时写入一个session,有一个SessionID的字段和当前这个验证码对应。因此当用户输入用户名、密码和验证码的时候,浏览器自动把存有session信息的cookie发送到服务器,服务器基于Session能够判断当前这个验证码确实是A用户应该要输入的。angularjs

缺点:为了考虑到后续和其余系统集成,同时后台部署是多台服务器,采用的API网关。已经使用了Token,若是为了验证码这个功能,引入Session,有点得不偿失。后端

3.无Session解决方案

不能使用Session,那只能考虑无Session的方案。要同时获取验证码和验证码对应的一个id值。做为前端的我,第一反应是经过AngularJS中的$http请求去获取。可是后台验证码是直接读取图片返回二进制流格式给到前端,因此不能额外返回一个ID字段。后端开发同事就说,那在Response Header里面返回一个id的字段,和验证码的值相关联起来。到如今听起来一切都很顺利。前端代码以下:浏览器

//控制器层代码 $scope.getCaptcha = function () { loginService.getCaptcha().success(function (response, status, headers) { $scope.id = headers().id; if (response.size > 0) { $scope.verificationImage = window.URL.createObjectURL(response); } else { toastr.error("获取验证码失败:" + response.message); } }).error(function (response) { console.log(response); }); } //服务层代码 getCaptcha: function () { return $http({ method: "GET", responseType: "blob", url: AppConfig.userServerUrl + "/user/Captcha/request" }); },

前端AngularJS代码没法获取header头部额外字段,能获取的字段以下:安全

在stackoverflow上搜索一番,解决办法是后台须要设置容许前端浏览器能获取header头部里面的字段。后台同事修改以后,response header里面信息以下图所示:服务器

同域和跨越解决办法:How to read response headers in angularjs?cookie

4.IE9下的bug

觉得大功告成,而后在IE9浏览器上测试一下,发现没法加载到验证码,并且控制台报错误。折腾半天,发现IE9不支持window.URL.createObjectURL();,并且AngularJS发送请求加载二进制流文件就报错。

为了支持IE9,目前解决方法是让后台不返回二进制流文件,而是返回base64编码的字符串,这样IE9也是支持的。

5.可选一种方式

和以前同事交流一番,同事提出了一个可选的方案。由于咱们在请求验证码的时候有2个内容,一个是验证码id,一个验证码图片。其实验证码id能够在前端使用随机数生成一个,而后前端把这个id传入后台,后台根据这个id,而后加一些特殊字符,拼接以后一个惟一字符,同时生成一个图片,这个惟一字符和这个验证码图片关联起来,而后将图片返回base64编码内容返回到前端。这种能够不须要前端发送Ajax请求,直接在图片上使用ng-src

<img ng-src="http://www.example.com?uid=1001cmss" >
相关文章
相关标签/搜索