java实用技巧

java实用技巧> **1.首先根据官方文档得知,**
> **2.将token、timestamp、nonce三个参数进行字典序排序**

欢迎大家来到IT世界,在知识的湖畔探索吧!

服务器配置

java实用技巧

java实用技巧

1.首先根据官方文档得知,

2.将token、timestamp、nonce三个参数进行字典序排序

3.将三个参数字符串拼接成一个字符串进行sha1加密

4.开发者获得加密后的字符串可与signature对比,标识该请求来源于

5.验证url需要开发者登录官方开发平台扫码获得填写。

详细代码如下:

public void validate(String wxToken, CheckModel tokenModel,HttpServletResponse response){

String signature = tokenModel.getSignature();

Long timestamp = tokenModel.getTimestamp();

Long nonce =tokenModel.getNonce();

String echostr = tokenModel.getEchostr();

if(signature!=null&&timestamp!=null&nonce!=null) {

String[] str = {wxToken, timestamp+””, nonce+””};

Arrays.sort(str); // 字典序排序

String bigStr = str[0] + str[1] + str[2];

// SHA1加密

String digest = EncoderHandler.encode(“SHA1”, bigStr).toLowerCase();

// 确认请求来至

if (digest.equals(signature)) {

//最好此处将echostr存起来,以后每次校验消息来源都需要用到

try {

System.out.println(“成功返回 echostr:” + echostr);

response.getWriter().write(echostr);

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

else{

System.out.println(“no”);

}

}

}

开发者token校验完成之后,获取accesstoken。access_token是的全局唯一票据,调用各接口时都需使用access_token。开发者需要进行妥善保存。

access_token的存储至少要保留512个字符空间。

access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的 access_token失效。

如果第三方不使用中控服务器,而是选择各个业务逻辑点各自去刷新access_token,那么就可能会产生冲突,导致服务不稳定。

可以使用AppID和AppSecret调用本接口来获取access_token。AppID和AppSecret可在获得(需要已经成为开发者,且帐号没有异常状态)。注意调用所有接口时均需使用https协议。

access_token的有效期是7200秒(两小时),在有效期内,可以一直使用,只有当access_token过期时,才需要再次调用接口 获取access_token。在理想情况下,一个7×24小时运行的系统,每天只需要获取12次access_token,即每2小时获取一次。如果在 有效期内,再次获取access_token,那么上一次获取的access_token将失效。

目前,获取access_token接口的调用频率限制为2000次/天,如果每次发送客服消息、获取用户信息、群发消息之前都要先调用获取 access_token接口得到接口访问凭证,这显然是不合理的,一方面会更耗时(多了一次接口调用操作),另一方面2000次/天的调用限制恐怕也不 够用。因此,在实际应用中,我们需要将获取到的access_token存储起来,然后定期调用access_token接口更新它,以保证随时取出的 access_token都是有效的。接口调用请求说明

http请求方式: GET

https://api.&&.》》.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

参数说明

参数

是否必须

说明

grant_type

获取access_token填写client_credential

appid

第三方用户唯一凭证

secret

第三方用户唯一凭证密钥,即appsecret

返回说明

正常情况下,会返回下述JSON数据包:

{“access_token”:”ACCESS_TOKEN”,”expires_in”:7200}

参数

说明

access_token

获取到的凭证

expires_in

凭证有效时间,单位:秒

错误时返回错误码等信息,JSON数据包示例如下(该示例为AppID无效错误):

{“errcode”:40013,”errmsg”:”invalid appid”}

2.获取accesstoken

主要思想:利用httpclient等工具模拟浏览器向服务器发送请求,如果成功,则获取

public static AccessToken getAccessToken(String appID, String appScret) {

AccessToken token = new AccessToken();

// 访问服务器

Stringurl=”https://api..qq.com/cgi-bin/token?grant_type=client_credential&appid=” + appID + “&secret=”+ appScret;

HttpClient httpClient = new DefaultHttpClient();

try {

HttpGet httpget = new HttpGet(url);

HttpResponse response = httpClient.execute(httpget);

HttpEntity httpEntity = response.getEntity();

// String string = httpEntity.toString();

// System.out.println(string);

// JSONObject json = JSONObject.fromObject(string);

//取属性值

String json1=EntityUtils.toString(httpEntity);

JSONObject json = JSONObject.fromObject(json1);

token.setAccess_token(json.getString(“access_token”));

SimpleDateFormat df = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);

String save_time=df.format(new Date());

token.setSave_time(save_time);

token.setExpire_time(json.getString(“expires_in”));

} catch (MalformedURLException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

finally {

httpClient.getConnectionManager().shutdown();

}

return token;

}

3.自定义菜单

获取accesstoken之后,就可以进行自定义菜单的创建。这里要注意的是要进入官方网站获取appId和appScret。利用这两个字段值进行自定义菜单的创建。

public static int createMenu(Menu menu) {

String jsonMenu = JSONObject.fromObject(menu).toString();

int status = 0;

// 凭证和秘钥

String appID = “########”;

String appScret = “&&&&&&&&&&&&”;

System.out.println(“菜单:” + jsonMenu);

String path = “https://api.weixin.qq.com/cgi-bin/menu/create?access_token=”

+ AccessTokenUtil.getAccessToken(appID, appScret).getAccess_token();

// 修改菜单时只需要修改它的accesstoken,利用accesstoken工具类发送一个http请求

// String

// path=”https://api.&&.qq.com/cgi-bin/menu/create?access_token=qHbUDio1PuPqh-cWLAiRAl7p761_0p8yqJWFIXe9lWwmAynM1oXJ0mctjtPLsf3Ga0gZonoUBZ7JF5KESp9vthgMkEj6FyRILxeC6a9Ll4UfrDIJmJSDbb2dEI6fcEk1JLSeABAVXE”;

try {

URL url = new URL(path);

HttpURLConnection http = (HttpURLConnection) url.openConnection();

http.setDoOutput(true);

http.setDoInput(true);

http.setRequestMethod(“POST”);

http.setRequestProperty(“Content-Type”, “application/x-www-form-urlencoded”);

http.connect();

OutputStream os = http.getOutputStream();

os.write(jsonMenu.getBytes(“UTF-8”));

os.close();

InputStream is = http.getInputStream();

int size = is.available();

byte[] bt = new byte[size];

is.read(bt);

String message = new String(bt, “UTF-8”);

JSONObject jsonMsg = JSONObject.fromObject(message);

status = Integer.parseInt(jsonMsg.getString(“errcode”));

} catch (MalformedURLException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

return status;

}

注意的是菜单的创建有缓存时间,所以要想即时查看,要取消关注再重新关注即可观察。click类型的菜单有key属性,而view类型的菜单没有key属性,与之对应的是url属性

用户订单创建时候注意,view和click的区别。View是可以直接跳转的url,而click是在后台进行判断的,其本身具有key值,开发者在后台进行字符串的处理,一般返回图文消息体,图文消息体中镶嵌跳转url。Ps:最重要的一点,不能请求重定向和请求转发,即跳转权不在开发者手里。

4.自定义回复消息

接入接口,如果是get请求,则进行第一次握手验证ps:第一步进行的验证,如果是post的话,则进行自定义消息回复,通俗讲就是当你第一次握手在网站填写的url,这个url就是一个入口,以后每次在客户端进行的操作的反馈都将发送到这个url上进行验证。

利用注解xml,将受到的消息和要返回的消息都用Xsteam进行构造。接受的消息体xml格式如下:

@XStreamAlias(“xml”)

public class InputMessage implements Serializable {

/**

*

*/

private static final long serialVersionUID = 1L;

@XStreamAlias(“ToUserName”)

private String ToUserName;

@XStreamAlias(“FromUserName”)

private String FromUserName;

@XStreamAlias(“CreateTime”)

private Long CreateTime;

@XStreamAlias(“MsgType”)

private String MsgType ;

@XStreamAlias(“MsgId”)

private Long MsgId;

// 文本消息

@XStreamAlias(“Content”)

private String Content;

// 图片消息

@XStreamAlias(“PicUrl”)

private String PicUrl;

// 位置消息

@XStreamAlias(“LocationX”)

private String LocationX;

@XStreamAlias(“LocationY”)

private String LocationY;

@XStreamAlias(“Scale”)

private Long Scale;

@XStreamAlias(“Label”)

private String Label;

// 链接消息

@XStreamAlias(“Title”)

private String Title;

@XStreamAlias(“Description”)

private String Description;

@XStreamAlias(“Url”)

private String URL;

// 语音信息

@XStreamAlias(“MediaId”)

private String MediaId;

@XStreamAlias(“Format”)

private String Format;

@XStreamAlias(“Recognition”)

private String Recognition;

// 事件

@XStreamAlias(“Event”)

private String Event;

@XStreamAlias(“EventKey”)

private String EventKey;

@XStreamAlias(“Ticket”)

private String Ticket;

回复消息要进行CDATA认证,编写一个注解用于实现这个功能。代码如下:

/**

* @author dingjianlei

* 自动回复消息的xml要经过CDATA的验证,此注解实现了CDATA验证

*/

@Retention(RetentionPolicy.RUNTIME)

@Target({ ElementType.FIELD })

public @interface XStreamCDATA {

}

ps:

自动回复消息格式体。跟inputMessage一样,利用注解进行xml格式的设置,回复的xml格式信息要经过CDATA 验证,

详细参考文档http://blog.csdn.net/lyq8479/article/details/8952173

5.绑定用户信息 用OpenID绑定即可

接口中虽然没给用户的账号,但给了用户的OpenID,这个OpenID对一个是唯一的,测试也证明不会改变,也就是说同一个号和同一个号交互,我们得到的OpenID是不会变的,因此,可以用OpenID作为用户的身份标识。

如何绑定

在里面给用户一个验证链接,用户点击链接,会用内嵌的浏览器打开这个链接,然后就是一般的网页登录验证界面,我们通过HTTP(S)获取用户输入的系统用户名与密码,验证通过后完成绑定。 具体如何生成链接和如何传递OpenID下面详述。

如何生成绑定链接

绑定涉及到用户的身份甚至利益,所以需要注意安全性。我们需要绑定的是OpenID和系统用户,系统用户名是用户直接在链接页面输入后通过HTTP(S)传给我们的,这没有问题。OpenID对用户来说透明,用户不会传给我们,我们也只有在用户发消息时才可获得OpenID,所以很明显,OpenID需要包含在生成的链接中,至于需不需要对OpenID作加密就看你自己了,我觉得这不重要,更为重要的是要在链接中带上签名和加上时间戳。因为我们需要确认这个链接是由我们服务端生成的,用户自己或者其他人不能够伪造出这个链接,加上时间戳是为了给这个链接一个过期时间,如果不限制过期时间,假设用户绑定后这个链接通过某种方式被别人知道,那么这个人就可以把自己的账号与用户的号绑定。所以我采取的方法是用OpenID、过期时间再加上一个密钥生成签名,生成签名的方法和服务器接口验证时的签名方法类似(密钥最好另选一个只有自己知道的)。

如何传递OpenID

有了绑定链接,用户点了绑定链接,但这只是第一步,第二步我们需要在用户在链接页面提交登录请求后进行验证,OpenID怎么传到第二步中呢?有人说了,这还不简单,在登录表单中加一个隐藏域放用户的OpenID一起提交给验证的Handler不就OK了,那我只能说很遗憾,你前面所做的安全工作都白费了,一旦A用户的OpenID泄漏,B用户就可以把自己的账号与A用户的号绑定了。所以永远不要相信客户端提交的东西。我的方法是当用户点击生成链接后,在链接页载入时,将OpenID存到session中,因为这个session是没法伪造的(cookie被盗除外),所以只有点击这个链接的用户的session中才会有链接中包含的OpenID。

关于服务器签名多说一句

大家都知道消息接口验证时微信会向我们服务器发一个GET请求,在其中带上只有我们和务器知道的签名,我们在请求处理Handler中会验证这个签名,这点大家无异议;消息接口验证通过后,就会把用户发的消息以POST的方式发给我们,很多人可能会在这里忽视对签名的检查,从而给恶意者伪造用户请求的机会。在以POST方式传递用户的消息时,仍然会将签名信息附在URL参数中,我们在处理每一个POST请求时,第一步还是得像处理消息接口验证时一样,去对URL参数中的签名作验证,只有签名验证通过后才可去取POST的信息。

绑定流程的详细描述

我在上面说了基本方法,但不够详细,导致一些新手朋友还是不清楚具体如何操作,所以我在此尝试更加详细地描述整个过程的每一步:

数据库中建立用户OpenID和系统用户的绑定关系表,初始时为空。

用户交互时,你可以取到用户的OpenID。

检查数据表,如发现该OpenID没有绑定系统用户,则返回一个链接供用户在浏览器中打开,这个链接打开后类似于系统用户登录界面。

关键是链接的生成,链接需要带3个url参数:

1. 用户OpenID:因为你需要在绑定页面中取到是哪个用户想要绑定系统用户。

2. 时间戳timestamp:这是为了防止链接泄漏出去被恶意利用,具体来说就是一个你指定的过期时间,超过这个时间这个链接就失效了,用户只能再次获取。

3. 签名signature:这是为了保证此验证链接只有你才可能生成,用户及第三方均无法伪造。

签名的生成需要你有一个只有你知道的token(密钥,不要与设置在公众号里面的token相同),生成签名方法和验证服务器消息真实性类似。流程如下:

1. 将token、OpenID、timestamp三个参数进行字典序排序。

2. 将三个参数字符串拼接成一个字符串进行sha1加密,得到链接的signature参数。

用户打开某个绑定链接时,你首先验证链接的有效性,即按上述5.1和5.2中描述的同样的步骤得到signature与参数中的sinature对比,如果相同,则再检查链接是否超时,两步验证均通过,你就可以将用户的OpenID设置到用户的session中,然后你就可以渲染验证页面,让用户输入其系统用户名和密码以提交给你服务器进行验证。

在用户提交绑定验证请求后,你只需要检查session中有没有你设置的OpenID,没有自然无效,有的话就是要绑定的OpenID了,此时你可以把这个OpenID从session中删除了。然后你如果验证系统用户名和密码通过后,就把这个OpenID和系统用户绑定起来,加入到第1步中说的绑定关系表中。

完毕。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/22282.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们YX

mu99908888

在线咨询: 微信交谈

邮件:itzsgw@126.com

工作时间:时刻准备着!

关注微信