package edu.fudan.weixin.actions;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Results;
import org.apache.struts2.convention.annotation.Result;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.util.JSON;
import edu.fudan.eservice.common.smtp.SMTP;
import edu.fudan.eservice.common.smtp.ServiceMail;
import edu.fudan.eservice.common.struts.GuestActionBase;
import edu.fudan.eservice.common.utils.CommonUtil;
import edu.fudan.eservice.common.utils.Config;
import edu.fudan.eservice.common.utils.EncodeHelper;
import edu.fudan.eservice.common.utils.MongoUtil;
import edu.fudan.eservice.common.utils.OAuth2Helper;
import edu.fudan.weixin.utils.TACOAuth2Helper;
@ParentPackage(value = "servicebase")
@Namespace("/")
@Results({ @Result(location = "result.jsp") })
public class BindAction extends GuestActionBase {
/**
*
*/
private static final long serialVersionUID = 3364128562759884183L;
private String code;
private String state;
private String scope;
@Action("bindin")
public String input() {
Config conf = Config.getInstance();
byte[] bs = new byte[16];
new Random().nextBytes(bs);
String st = EncodeHelper.bytes2hex(bs);
// 放进一个使用EhCache维护的容器,当用户从微信的OAuth2.0拿到code后检查这个链接是不是由此链接生成的。
// CacheManager.getInstance().getCache("WXStates").put(new
// Element(String.valueOf(st), st));
// 使用Session检查st的合法性
getSession().put("wxstate", st);
try {
org.apache.struts2.ServletActionContext.getResponse().sendRedirect(
"https://open.weixin.qq.com/connect/oauth2/authorize?appid="
+ conf.get("weixin.appid")
+ "&redirect_uri="
+ URLEncoder.encode(conf.get("weixin.context")
+ "uisbind.act", "utf-8")
+ "&response_type=code&scope=snsapi_base&state="
+ st + "#wechat_redirect");
} catch (Exception e) {
e.printStackTrace();
}
return NONE;
}
@Action("uisbind")
public String uis() {
if (!CommonUtil.isEmpty(code) && !CommonUtil.isEmpty(state)
&& state.equals(getSession().remove("wxstate"))) {
Config conf = Config.getInstance();
// 获取微信的access_token
String urlstr = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="
+ conf.get("weixin.appid")
+ "&secret="
+ conf.get("weixin.secret")
+ "&code="
+ code
+ "&grant_type=authorization_code";
try {
String ret = CommonUtil.getWebContent(urlstr).toString();
DBObject retobj = (DBObject) JSON.parse(ret);
Object acctk = retobj.get("access_token");
if (!CommonUtil.isEmpty(acctk)) {
Object openid = retobj.get("openid");
// 设置Session
getSession().put("openid", openid);
DBCollection c = MongoUtil.getInstance().getDB()
.getCollection("Bindings");
DBObject obj = c
.findOne(new BasicDBObject("openid", openid));
if (CommonUtil.isEmpty(obj)) {
obj = new BasicDBObject().append("openid",
retobj.get("openid"));
}
obj.put("weixintoken", acctk);
obj.put("weixinexpired", System.currentTimeMillis() + 1000
* (int) retobj.get("expires_in"));
obj.put("weixinscope", retobj.get("scope"));
obj.put("wexinrefresh", retobj.get("refresh_token"));
c.save(obj);
// DBObject userinfo=new
// TACOAuth2Model().fetchUserinfo(obj);
// if (!CommonUtil.isEmpty(userinfo.get("user_id"))) {
// addActionMessage("UIS已经绑定为" + userinfo.get("user_id"));
// } else {
// 重定向到复旦TAC的授权页面
org.apache.struts2.ServletActionContext
.getResponse()
.sendRedirect(
conf.get("tac.codeurl")
+ "?response_type=code&scope="
+ URLEncoder.encode(
conf.get("tac.scope"),
"utf-8")
+ "&client_id="
+ conf.get("tac.clientid")
+ "&redirect_uri="
+ URLEncoder.encode(
conf.get("tac.redirecturi"),
"utf-8")
+ "&state="
+ EncodeHelper.bytes2hex(EncodeHelper
.encrypt(
"AES",
obj.get("openid")
.toString()
.getBytes(),
EncodeHelper
.hex2bytes(conf
.get("tac.enckey")),
null)));
return NONE;
// }
} else {
addActionError("Error in Weixin OAuth2 : "
+ retobj.get("errcode") + retobj.get("errmsg"));
}
} catch (Exception e) {
e.printStackTrace();
addActionError("Error in Weixin OAuth2: " + e.getMessage());
}
} else {
addActionError("请升级微信至最新版本,并确保在微信中打开相应链接,使用老版本微信或者外部浏览器无法获得完整信息。");
}
return SUCCESS;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Action("uisbinddo")
public String uisbinddo() {
Config conf = Config.getInstance();
// 获取access_token
try {
Map<String, Object> retobj = OAuth2Helper.getToken(code, false);
Object acctk = retobj.get("access_token");
if (!CommonUtil.isEmpty(acctk)) {
DBCollection c = MongoUtil.getInstance().getDB()
.getCollection("Bindings");
String openid = new String(EncodeHelper.dencrypt("AES",
EncodeHelper.hex2bytes(state),
EncodeHelper.hex2bytes(conf.get("tac.enckey")), null));
if (!CommonUtil.isEmpty(openid)
&& openid.equals(getSession().get("openid"))) {
DBObject idobj = c.findOne(new BasicDBObject("openid",
openid));
if (!CommonUtil.isEmpty(idobj)) {
BasicDBObject obj = new BasicDBObject();
obj.put("uistoken", acctk);
obj.put("uisexpired", System.currentTimeMillis() + 1000
* (int) retobj.get("expires_in"));
obj.put("uisscope", scope);
obj.put("uisrefresh", retobj.get("refresh_token"));
// 获取用户信息
retobj = TACOAuth2Helper.fetchUser(String
.valueOf(acctk));
if (!CommonUtil.isEmpty(retobj.get("user_id"))) {
Object email = retobj.get("email");
Object userid = retobj.get("user_id");
Object bds = idobj.get("binds");
if (!CommonUtil.isEmpty(bds) && bds instanceof List) {
Iterator i = ((List) bds).iterator();
while (i.hasNext()) {
Object o = i.next();
if (!CommonUtil.isEmpty(o)) {
DBObject bd = (DBObject) o;
if (CommonUtil.eq(userid,
bd.get("uisid")))
i.remove();
} else
i.remove();
}
} else {
bds = new BasicDBList();
idobj.put("binds", bds);
}
obj.put("uisid", userid);
obj.put("email", email);
obj.put("username", retobj.get("user_name"));
obj.put("usertype", retobj.get("user_type"));
((List) bds).add(obj);
addActionMessage("成功将此微信号与" + retobj.get("user_id")
+ "完成了绑定");
// 如果可以获取到Email发个通知
if (String.valueOf(userid).matches("\\d{7,}"))
email = userid + "@fudan.edu.cn";
if (!CommonUtil.isEmpty(email)) {
try {
SMTP smtp = new ServiceMail();
smtp.addTo(email.toString());
smtp.setTitle("微信账号与UIS账号绑定成功");
String mb = conf.get("bind.mail");
mb = mb.replaceAll("%uis%", String
.valueOf(retobj.get("user_id")));
DBObject user = MongoUtil
.getInstance()
.getDB()
.getCollection("weixinuser")
.findOne(
new BasicDBObject("openid",
openid));
if (!CommonUtil.isEmpty(user))
mb = mb.replaceAll("%nickname%", String
.valueOf(user.get("nickname")));
smtp.setMailbody(mb, false);
smtp.send();
} catch (Exception e) {
addActionError("Error in Send Mail:" + e);
}
}
} else {
addActionError("Error in TAC Resource:"
+ retobj.get("error"));
}
c.save(idobj);
}
} else {
addActionError("该绑定请求的来源中的微信账号信息与当前账号不匹配,可能存在安全风险,请通过“复旦信息办”微信公众账号获取最新的绑定链接!");
}
} else {
addActionError("Error in TAC OAuth2 : " + retobj.get("error"));
}
} catch (Exception e) {
e.printStackTrace();
addActionError("Error in TAC OAuth2: " + e.getMessage());
}
return SUCCESS;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
}