移动开发中必定会涉及后台API如何访问,如何控制访问权限,保证系统安全等问题。
介绍一下我最近本身作的一个移动端访问后端API的例子,例子写的很粗糙,可是基本实现了以token auth 为核心的demo。
在实现demo过程当中也找到了很多的好资料,这一篇《APP中用户验证方案》详细的介绍了APP用户验证的不一样方案。javascript
大致思路:html
APP登陆界面输入用户信息登陆;服务端验证登陆信息,验证成功,向APP端发送token,将token保存到数据库或者缓存服务器中;APP登陆成功后,每次调用后端API时都须要带着token、时间戳、sign(token+时间戳的md5字符串,sign能够本身定义算法以防止被盗用)信息,以便后台验证访问API权限;后端在接收到APP访问请求时,比对APP发送来的token与缓存服务器中已经存在的token是否一致,并验证token时效性。
好了,废话少说,上代码:前端
前端代码(APP,最近写的APP基本都是H5方式实现):java
<label>用户名</label> <input type="text" name="username" id="username" value="" /> <br/> <label>密码</label> <input type="password" name="password" id="password" value="" /> <input type="button" name="login" id="login" value="登陆" /> <script type="text/javascript"> document.getElementById("login").addEventListener('click',function () { //alert('hello'); //ajax提交验证信息到后端 var username = document.getElementById("username").value; var password = document.getElementById("password").value; var data = "{\"username\":\"" + username +"\",\"password\":\"" + password + "\"}"; var url = "/AppTest/loginServlet"; var wd = "123"; var headData = ["123","123456789012345","gsfgfgbdf"]; postData(url,data, headData,function (backdata) { if(backdata != null){ console.log("返回的信息为: " + backdata); } },wd); }); </script>
这里的ostData使用的是封装好的Ajax函数,下面一并放出代码:web
ajax.js:ajax
/*对ajax进行简易封装,便于每次调用,省去参数设置*/ function postData(url, data, headData, callback, waitingDialog) { mui.ajax(url,{ data:data, dataType:'json', type:'post', headers: { "token" : headData[0], "timesamp" : headData[1], "sign" : headData[2] }, contentType:"application/x-www-form-urlencoded; charset=utf-8", timeout:20000, success:callback, error:function(xhr,type,errorThrown){ //waitingDialog.close(); alert("<网络链接失败,请从新尝试一下>", "错误", "OK", null); } }); }
ajax中加上了headers参数,这里加headers参数的目的是,后台使用servlet+filter的方式控制访问,若是将token等其余参数直接和表单数据同时提交,filter在获取token信息后,servlet就不能获取到表单数据,这就比较尴尬了,或者后台使用AOP的方式控制访问权限 ,这个尚未来得及尝试。若是我能把token信息加到于表单数据不一样的存储区域就行了,Google后找到了能够把数据加到请求的header中能够实现将token数据与表单数据分离的效果。
过滤器(Java实现 JDK1.8 Tomcat8.5.6):redis
import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import me.wlc.wx.web.tool.Md5; /** * 使用注解标注过滤器 * @WebFilter将一个实现了javax.servlet.Filte接口的类定义为过滤器 * 属性filterName声明过滤器的名称,可选 * 属性urlPatterns指定要过滤 的URL模式,也可以使用属性value来声明.(指定要过滤的URL模式是必选属性) * urlPatterns="/*" 表示过滤掉全部请求 */ @WebFilter(filterName="AccessFilter",urlPatterns="/*") public class AccessFilter implements Filter { @Override public void destroy() { System.out.println("过滤器销毁"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("执行过滤操做"); HttpServletRequest req = (HttpServletRequest) request; String uri = req.getRequestURI(); System.out.println("uri is : " + uri); //对请求的uri(即api)进行判断,若是是登陆的uri则直接放行,若是是其余api则对sign进行验证操做 if( !uri.endsWith("loginServlet") ){ //从请求的url中取出token、时间戳、sign String token = req.getHeader("token"); String timesamp = req.getHeader("timesamp"); String sign = req.getHeader("sign"); System.out.println("sign is : " + sign); StringBuffer requestUrl = req.getRequestURL(); System.out.println("请求的Url是: " + requestUrl); //对token、timesamp 进行md5计算 String signMd5 = Md5.getMD5(token + timesamp); if(sign.equals(signMd5)){ //签名经过 chain.doFilter(request, response); }else{ //签名不经过,向app后端发送错误信息,提示从新登陆 } }else{ //登陆操做 chain.doFilter(request, response); } //请求经过 //chain.doFilter(request, response); } @Override public void init(FilterConfig arg0) throws ServletException { System.out.println("过滤器初始化"); } }
后端尚未实现验证token时效性功能,也没有将token存储到缓存服务器中,这些须要具体方案定下来之后再加上了。再说一句,生成的token保证token值惟一便可,可使用最方便的UUID(Java中)。算法
大致就是这样了,有问题随时提给我哦!数据库
PS:2018年9月28日更新
一直没有登陆查看留言,给留言板的各位兄弟道个歉,没有及时回复
token存储方案:json
方案一:使用session的超时时间来控制token的失效时间
方案二:使用redis存储token的失效时间
方案一适用于单机环境,能够做为小型系统的token时效性验证方案,此方案若处于分布式环境会致使session在分布式机器间的时间不一样步,但跟组里的其余工程师沟通,在分布式环境下是否是还能够同步session?
方案二适用于大型系统,还要使用redis服务,使用redis存储token但是实现快速读取token时效数据,若将toke失效时间存储到数据库中,频繁操做数据库,会影响数据库的响应时间,进而应用程序也会出现卡顿等状况。
另,token的失效时间应该设置多长须要根据所在项目的实际状况肯定。