这次要写一些restful的接口,在访问安全这一块最开始我想到用redis存储模拟session,客户端访问会带token过来模拟jsessionid,然后比对,但是这样会让token暴露在网络中,很不安全而且没有意义。

  • 其实可以用签名的方法来解决这个问题:

首先:client开通服务的时候,server会给它创建authKey和一个token,authKey相当于是公钥可以暴露在网络中,token是私钥不会暴露在网络中

然后:client请求服务端的时候在header中添加请求的时间戳,并且对发送的信息以及时间戳和token拼接起来的字符串进行签名(可以采用MD5或者SHA-0、SHA-1等)

最后:把签名串以及信息和header的信息发送到服务端,然后服务端会取出header信息以及签名串和信息,先对header里面的时间和服务器接收到的时间校验然后求差值如果大于多少秒就返回时间错误(防止重复攻击),然后在服务器端也对数据拼接签名,最后对比签名是否相等,如果不等就返回错误信息,如果相等下面就可以开始处理业务信息。

  • 刚写了份demo代码 结构如下:

  • 工程中使用springmvc发布服务,其中controller中的代码如下:
package com.lijie.api;import java.util.Calendar;import javax.servlet.http.HttpServletRequest;import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;import com.lijie.utils.Signature;/*** * @author Lijie**/
@Controller
public class ApiAuth {/*** 测试auth* @param request* @param authKey* @param sign* @param info* @return* @throws Exception*/@RequestMapping(value = "/api/auth/test", method = RequestMethod.POST)@ResponseBodypublic String testAuth( HttpServletRequest request, String authKey, String sign,String info) throws Exception {String reqTime = request.getHeader("ReqTime-Time");//这里的token应该是根据客户端那边传来的authKey从redis里面将token取出来,我这里直接写死了String token = "lijieauthtest01";String check = check(reqTime, info, token, sign);System.out.println("服务端:" + check);//do servicereturn check;}/*** 校验参数和签名* * @param reqTime* @param info* @param token* @param sign* @return* @throws Exception*/private String check(String reqTime, String info, String token, String sign) throws Exception {if (StringUtils.isEmpty(reqTime)) {return "头部时间为空";}if (StringUtils.isEmpty(info)) {return "信息为空";}if (StringUtils.isEmpty(token)) {return "没有授权";}if (StringUtils.isEmpty(sign)) {return "签名为空";}long serverTime = Calendar.getInstance().getTimeInMillis();long clientTime = Long.parseLong(reqTime);long flag = serverTime - clientTime;if (flag < 0 || flag > 5000) {return "时间错误";}String allStr = info + reqTime + token;String md5 = Signature.md5(allStr);if (sign.equals(md5)) {System.out.println("服务端未签名时为:" + allStr);System.out.println("服务端签名之后为:" + md5);return "签名成功";}return "签名错误";}}
  • 测试httpclient请求的代码如下:
package com.lijie.test;import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.junit.Test;import com.lijie.utils.Signature;public class MyTest {private static final String token = "lijieauthtest01";@Testpublic void authTest() throws Exception {//创建一个httpclient对象CloseableHttpClient client = HttpClients.createDefault();//创建一个post对象HttpPost post = new HttpPost("http://localhost:8080/api/auth/test");//创建一个Entity,模拟表单数据List<NameValuePair> formList = new ArrayList<>();//添加表单数据long clientTime = Calendar.getInstance().getTimeInMillis();String info = "这是一个测试 restful api的 info";String reqStr = info + clientTime + token;formList.add(new BasicNameValuePair("authKey", "1000001"));formList.add(new BasicNameValuePair("info", info));String md5 = Signature.md5(reqStr);formList.add(new BasicNameValuePair("sign", md5));//包装成一个Entity对象StringEntity entity = new UrlEncodedFormEntity(formList, "utf-8");//设置请求的内容post.setEntity(entity);//设置请求的报文头部的编码post.setHeader(new BasicHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"));//设置期望服务端返回的编码post.setHeader(new BasicHeader("Accept", "text/plain;charset=utf-8"));//设置时间post.setHeader(new BasicHeader("ReqTime-Time", clientTime + ""));System.out.println("客户端未签名时为:" + reqStr);System.out.println("客户端签名之后为:" + md5);//执行post请求CloseableHttpResponse response = client.execute(post);//获取响应码int statusCode = response.getStatusLine().getStatusCode();if (statusCode == 200) {//获取数据String resStr = EntityUtils.toString(response.getEntity());//输出System.out.println("请求成功,请求返回内容为: " + resStr);} else {//输出System.out.println("请求失败,错误码为: " + statusCode);}//关闭response和clientresponse.close();client.close();}
}
  • Signature类其实就是MD5加密的一个工具类,代码如下:
package com.lijie.utils;import java.security.MessageDigest;/*** * @author Lijie**/
public class Signature {public static String md5(String data) throws Exception {// 将字符串转为字节数组byte[] strBytes = (data).getBytes();// 加密器MessageDigest md = MessageDigest.getInstance("MD5");// 执行加密md.update(strBytes);// 加密结果byte[] digest = md.digest();// 返回return byteArrayToHex(digest);}private static String byteArrayToHex(byte[] byteArray) {// 首先初始化一个字符数组,用来存放每个16进制字符char[] hexDigits = {    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D','E', 'F' };// new一个字符数组,这个就是用来组成结果字符串的(解释一下:一个byte是八位二进制,也就是2位十六进制字符(2的8次方等于16的2次方))char[] resultCharArray = new char[byteArray.length * 2];// 遍历字节数组,通过位运算(位运算效率高),转换成字符放到字符数组中去int index = 0;for (byte b : byteArray) {resultCharArray[index++] = hexDigits[b >>> 4 & 0xf];resultCharArray[index++] = hexDigits[b & 0xf];}// 字符数组组合成字符串返回return new String(resultCharArray);}}
  • 开启服务,测试访问,其中服务端输出:

  • 客户端输出:

RestFul接口的安全验证事例相关推荐

  1. 关于Go语言在服务端做Restful接口和socket通信

    转载自: http://xiaorui.cc/2014/10/25/%e5%85%b3%e4%ba%8ego%e8%af%ad%e8%a8%80%e5%9c%a8%e6%9c%8d%e5%8a%a1% ...

  2. spark-jobserver介绍: 提供了一个 RESTful 接口来提交和管理 spark 的 jobs、jars 和 job contexts

    spark-jobserver Spark-jobserver 提供了一个 RESTful 接口来提交和管理 spark 的 jobs.jars 和 job contexts.这个项目包含了完整的 S ...

  3. python前端调用后端模型_前端调用后端的方法(基于restful接口的mvc架构)

    1.前端调用后台: 建议用你熟悉的一门服务端程序,例如ASP,PHP,JSP,C#这些都可以,然后把需要的数据从数据库中获得,回传给客户端浏览器(其实一般就是写到HTML中,或者生成XML文件)然后在 ...

  4. php调用restful接口_如何使用PHP编写RESTful接口

    这是一个轻量级框架,专为快速开发RESTful接口而设计.如果你和我一样,厌倦了使用传统的MVC框架编写微服务或者前后端分离的API接口,受不了为了一个简单接口而做的很多多余的coding(和CTRL ...

  5. 【Restful接口】restful接口的两种使用方式

            小编最近的项目是好几个团队的一块合作,由于项目大,功能多,各个团队负责的东西不同,我的团队除了自己的开发前端和后端外,还负责给别的团队提供后端支持,在这里就用上了restful接口. ...

  6. RESTful接口入门

    RESTful产生背景 从下面的图片可以看出,当我们需要把相同的数据展示到不同的界面上时,提供一个可以访问后台的接口,前台只负责将数据友好的,华丽的展示出来即可.而不需要为每一个前台都实现很多的后台逻 ...

  7. 想要年薪百万,阿里Sentinel支持RESTful接口都搞不定?

    最近正准备用阿里Sentinel,发现RESTful接口支持的不是很好.有些童鞋可能对Sentinel不是很了解,我们先简单介绍一下. Sentinel简介 Sentinel是一套阿里巴巴开源的流量防 ...

  8. restful接口设计规范学习

    1.接口编程 1 背景 随着互联网的发展, 尤其是移动互联为代表的Web3.0时代. 客户端层出不穷, 以APP.微信.PC浏览器为代表, 服务端业务逻辑是基本一致的.那么有没有一种方式可以做到&qu ...

  9. php调用restful接口_PHP restful 接口

    首先我们来认识下RESTful Restful是一种设计风格而不是标准,比如一个接口原本是这样的: http://www.test.com/user/view/id/1 表示获取id为1的用户信息,如 ...

最新文章

  1. PWA之push服务
  2. android 内置app,android9.0内置APP
  3. MySQL INT、TINYINT、SMALLINT、MEDIUMINT、BIGINT(整数类型)
  4. 315汽车大型排雷现场,数据总结避雷规律
  5. Flutter入坑分享
  6. Java 11快多少?
  7. Spring Boot 官方文档学习(一)入门及使用
  8. np.c_和np.r_
  9. centos 安装qrcode  二维码
  10. winxp netbeui install
  11. 电子罗盘在终端的应用
  12. excel双纵坐标轴展示的方法
  13. 技能证里的天花板-阿里云云计算架构师ACE认证将全面升级!
  14. Java面向对象 - String类
  15. 安装win7时缺少所需的CDDVD驱动器设备驱动程序
  16. c2c开店流程图_c2c的主要业务流程图以及路线?
  17. go语言 json -转载
  18. 手机电路板文件_PCB工程师必看,从图纸到成品,电路板的制作只需这三大流程...
  19. 美容美发美甲店做活动效果提升30%的营销方案18个套路
  20. Linux系统简介分区基础命令(ADMIN01-2)

热门文章

  1. 2D转换transform--rotate旋转(日志)
  2. Jenkins 插件 Extended Choice Parameter
  3. 【操作系统】保姆级教程(VMware)Ubuntu+qemu+xv6安装调试
  4. HDU 2096 小明A+B
  5. 关于人生中的第一篇博客
  6. 在MySQL中创建实现自增的序列(Sequence)的教程
  7. [Android] ListView实现隔行变色(一)
  8. ILITEK touch driver
  9. 链表综合案例(超市购物车)
  10. 在php输出字符串时执行html标签,把字符串作为PHP代码执行