这段时间做新的Android项目的client和和REST API通讯框架架构设计。使用了非常多新技术,终于的方案也相当简洁优雅。client仅仅须要传Java对象,server端返回json字符串,自己主动解析成Java对象, 无状态安全验证基于JWT实现,JWT规范的细节能够參考我前面的文章。

JWT的token和数据防篡改签名统一放在HTTP Header中。这样就实现了对请求内容和返回结果的无侵入性,server端也能够在全局过滤器中统一处理安全验证。

Androidclient使用了Volley网络请求框架和Gson解析库。基于这2个Goolge的框架封装了自己的GsonRequest网络请求基类。 网络请求类没有做特别处理,网络response返回消息,做了个带泛型的基类。统一处理错误码,消息和返回结果,Android端的代码例如以下:

package com.zxt.network;

/**
* HTTP返回基类。返回正确结果status>0,错误结果status<0,
* message为server端返回消息,client直接显示
* T data为返回的json对象或数组,自己主动解析为Java对象
* errorCodes为server端返回的Dubbo接口错误码。逗号分隔,仅做调试用途
* Created by zhangxitao on 15/8/17.
*/
public class BaseResponse<T> {
public int status;
public String message;
public String errorCodes;
public T data ; public int getStatus() {
return status;
} public void setStatus(int status) {
this.status = status;
} public String getMessage() {
return message;
} public void setMessage(String message) {
this.message = message;
} public String getErrorCodes() {
return errorCodes;
} public void setErrorCodes(String errorCodes) {
this.errorCodes = errorCodes;
} public T getData() {
return data;
} public void setData(T data) {
this.data = data;
}
}
package com.zxt.network;

import android.text.TextUtils;
import android.util.Log; import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.toolbox.HttpHeaderParser;
import com.google.gson.Gson;
import com.qianmi.qmpos.AppConfig; import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map; /**
* Gson请求类,传入请求对象和返回类名,返回解析好的对象,封装JWT安全验证,数据签名
* @param <T>
*/
public class GsonRequest<T> extends Request<T> { private static final String TAG = "GsonRequest"; private final Listener<T> mListener; private Gson mGson; private Class<T> mClass;
private Object mRequest;
private String mBody; public GsonRequest(int method, String url, Object request, Class<T> clazz, Listener<T> listener, ErrorListener errorListener) {
super(method, url, errorListener);
mGson = new Gson();
mClass = clazz;
mListener = listener;
mRequest = request;
if (null != request) {
mBody = mGson.toJson(mRequest);
}
} public GsonRequest(String url, Object request, Class<T> clazz, Listener<T> listener, ErrorListener errorListener) {
this(Method.POST, url, request, clazz, listener, errorListener);
Log.d(TAG, "-----url is:" + url);
} @Override
public byte[] getBody() throws AuthFailureError {
if (null == mRequest) {
return null;
}
Log.d(TAG, "-----request json: " + mBody);
return mBody.getBytes();
} @Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
return Response.success(mGson.fromJson(jsonString, mClass), HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
} @Override
protected void deliverResponse(T response) {
mListener.onResponse(response);
Log.i(TAG, "-----response:" + new Gson().toJson(response));
} @Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> extraHeaders = new HashMap<>();
extraHeaders.put("Content-Type", "application/json");
extraHeaders.put("Accept", "application/json"); //Data Sign
if (!TextUtils.isEmpty(mBody)) {
extraHeaders.put("Sign", MD5Util.stringToMD5(AppConfig.SIGN_SECRET + mBody + <span style="font-family: Arial, Helvetica, sans-serif;">AppConfig.SIGN_SECRET </span><span style="font-family: Arial, Helvetica, sans-serif;">));</span>
}
//JWT token
if (!TextUtils.isEmpty(AppConfig.TOKEN)) {
extraHeaders.put("Authorization", "Bearer " + AppConfig.TOKEN);
}
Log.d(TAG, "-----extra headers: " + extraHeaders.toString()); return extraHeaders;
}
}

一个简单的调用样例

  LoginRequest loginRequest = new LoginRequest();

        loginRequest.setNickName(username);
loginRequest.setPassword(RSAUtils.getEncryptPwd(password)); Request request = new GsonRequest<LoginResponse>(
AppConfig.SERVER_URL + "/login",loginRequest, LoginResponse.class,
new Response.Listener<LoginResponse>() {
@Override
public void onResponse(LoginResponse resp) {
L.d("TAG", "user is " + resp.data);
//TODO }
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("TAG", error.getMessage(), error);
}
});
mVolleyQueve.add(request)

server端使用Spring Boot,Spring MVC。 JPA。JWT等技术构建。相同的简洁优雅, Spring Boot微服务技术确实简化了接口的开发,能够做到零XML配置文件。因为临时权限这边不够复杂。临时没有引入Spring Security框架,安全验证通过一个全局的过滤器完毕。API接口通过使用@RestController注解实现。详细的參考代码例如以下:

import com.zxt.domain.BaseResponse;
import com.zxt.domain.pos.Device;
import com.zxt.service.DeviceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController; @RestController
@RequestMapping("/api/device")
public class DeviceController { @Autowired
DeviceService deviceService; @RequestMapping("activate")
@ResponseBody
public BaseResponse activate(@RequestBody @Validated Device device) { try {
this.deviceService.activateDevice(device);
} catch (Exception e) {
return new BaseResponse(-1,"activate failed");
} return new BaseResponse(1,"device activated");
} }

Google Volley这个框架除了攻克了频繁网络请求情景的性能问题之外。可定制性也是非常强大的,通过定制我们自己的GsonRequest类,实现了对数据传输无侵入性的JWT安全验证和数据防篡改, 双向自己主动化的JSON解析能力,极大的简化了Android网络App的开发工作。

基于Volley,Gson封装支持JWT无状态安全验证和数据防篡改的GsonRequest网络请求类的更多相关文章

  1. 开箱即用 - jwt 无状态分布式授权

    基于JWT(Json Web Token)的授权方式 JWT 是JSON风格轻量级的授权和身份认证规范,可实现无状态.分布式的Web应用授权: 从客户端请求服务器获取token, 用该token 去访 ...

  2. jwt 无状态分布式授权

    基于JWT(Json Web Token)的授权方式 JWT 是JSON风格轻量级的授权和身份认证规范,可实现无状态.分布式的Web应用授权: 从客户端请求服务器获取token, 用该token 去访 ...

  3. 【SpringSecurity系列2】基于SpringSecurity实现前后端分离无状态Rest API的权限控制原理分析

    源码传送门: https://github.com/ningzuoxin/zxning-springsecurity-demos/tree/master/01-springsecurity-state ...

  4. 教你如何实现微信小程序与.net core应用服务端的无状态身份验证

    随着.net core2的发布,越来越多人使用.net core2开发各种应用服务端,下面我就结合自己最近开发的一款小程序,给大家分享下,怎么使用小程序登录后,小程序与服务端交互的权限控制. .net ...

  5. block传值以及利用block封装一个网络请求类

    1.block在俩个UIViewController间传值 近期刚学了几招block 的高级使用方法,事实上就是利用block语法在俩个UIViewController之间传值,在这里分享给刚開始学习 ...

  6. ASP.NET Core 使用 JWT 搭建分布式无状态身份验证系统

    为什么使用 Jwt 最近,移动开发的劲头越来越足,学校搞的各种比赛都需要用手机 APP 来撑场面,所以,作为写后端的,很有必要改进一下以往的基于 Session 的身份认证方式了,理由如下: 移动端经 ...

  7. 【SpringSecurity系列1】基于SpringSecurity实现前后端分离无状态Rest API的权限控制

    源码传送门: https://github.com/ningzuoxin/zxning-springsecurity-demos/tree/master/01-springsecurity-state ...

  8. Xamarin.Android之封装个简单的网络请求类

    一.前言 回忆到上篇 <Xamarin.Android再体验之简单的登录Demo> 做登录时,用的是GET的请求,还用的是同步, 于是现在将其简单的改写,做了个简单的封装,包含基于Http ...

  9. beego应用做纯API后端如何使用jwt实现无状态权限验证

    jwt是什么,可以百度下其它文章,我原来看到一个讲的详细的,现在找不到了.先简单介绍下我个人的理解,就是一个token,只不过通过加密解密的手段,能让这一串字符带有一些简单的信息.这样解密jwt后不用 ...

随机推荐

  1. PS如何批量整理图片大下

    https://jingyan.baidu.com/article/cdddd41cc7849853cb00e193.html

  2. 使用Micrisoft.net设计方案 第三章Web表示模式 Web模式集群详细介绍 Observer(观察器)

    在面向对象的编程中,对象同时包含数据和行为,这两者一起表示业务域的特定方面.使用对象生成应用程序的优点之一是可以将所有数据操作封装在对象内.这样, 就使对象成为独立的单位,并增加了在其他应用程序中重用 ...

  3. 提取header头进行模块化处理

    在进行爬取网上东西的时候一般网站都做了UA的过滤,解决办法就是在代码中加入. 所以才有了本篇提取header头信息单独写成一个模块或者说是函数/类的想法,直接上示例 1.把UA头信息在浏览器中复制出来 ...

  4. JavaScriptav数据类型和变量

    数据类型 计算机顾名思义就是可以做数学计算的机器,因此,计算机程序理所当然地可以处理各种数值.但是,计算机能处理的远不止数值,还可以处理文本.图形.音频.视频.网页等各种各样的数据,不同的数据,需要定 ...

  5. linux 下mysql无法启动 mysql.sock

    在公司装的一键安装的lnmp环境,启动mysql时候发现mysql.sock不存在, 然后我进行查找  最后在  /usr/local/mysql/bin/mysql_safe  重新启动下 然后启动 ...

  6. Git 分支使用

    一个主分支肯定是不够用的,不同的开发最好放在不同的分支上,在最后进行合并,不然在开发中会相互干扰. PS:环境Window xp,Git-1.8.4-preview20130916(http://gi ...

  7. 搜索--P1101 单词方阵

    题目描述 给一n×n的字母方阵,内可能蕴含多个"yizhong"单词.单词在方阵中是沿着同一方向连续摆放的.摆放可沿着 8 个方向的任一方向,同一单词摆放时不再改变方向,单词与单词 ...

  8. Qt 给QWidget添加工具栏

    在Qt中,给主窗口(QMainWindow类)添加工具栏非常方便,直接使用addToolBar 即可,如下所示: fileToolBar = addToolBar(tr("&File ...

  9. 洛谷——P3275 [SCOI2011]糖果

    P3275 [SCOI2011]糖果 差分约束模板题,基本思路就是$d[v]+w[v,u]<=d[u]$,$Spfa$更新方法, 有点套路的是要建立原点,即图中不存在的点来向每个点加边,但同样这 ...

  10. buf.readFloatBE()

    buf.readFloatBE(offset[, noAssert]) buf.readFloatLE(offset[, noAssert]) offset {Number} 0 noAssert { ...