您的位置:首页 > 移动开发 > 微信开发

微信登陆Web应用解决方案

2016-02-18 11:11 711 查看
1.PC端



2.移动端



3.接入流程参考微信登录Web技术接入参考

注意写入事物回滚机制(因为涉及到操作多张表避免问题,)

接入微信登陆参考代码

1.微信开放平台回调函数

/**
* @param code  微信开放平台重定向这里,携带的code码
* @param state 来自PC端还是Mobile端
*
* @author simon
* @date 2016/02/24
*/
@GET
@Path("wxlogin")
public void wxlogin(@QueryParam("code") String code,
@QueryParam("state") String state,
@Context HttpServletRequest request,
@Context HttpServletResponse response) throws Exception {
if (!StringUtils.isEmpty(code)) {
//1.根据code请求access_token
Map<String, Object> map = CodeUtils.get_access_token(code);
String access_token = map.get("access_token").toString();
String openid = map.get("openid").toString();
//2.使用access_token去请求用户信息
Map<String, Object> userinfoMap = CodeUtils.get_userinfo(access_token, openid);
if (LuoboAppContext.currentUser() != null) {
WeichatBind weichatBind = new WeichatBind();
weichatBind.setUnionid(userinfoMap.get("unionid").toString());
weichatBind.setUserId(LuoboAppContext.currentUser().getId());
userService.createBind(weichatBind);//完成绑定
if(state.equals("01")){
response.sendRedirect("http://www.jkgst.com/main.html#!/user/base");//重定向到PC端页面
}else{
response.sendRedirect("http://www.jkgst.com/m/#!/user/base");//重定向到移动端页面
}
} else {
//当前为登陆操作,去绑定表查询该微信号是否已经绑定过
WeichatBind weichatBind = userService.getByUnionid(userinfoMap.get("unionid").toString());
if (weichatBind != null) {
//用户已经绑定过
User user = userService.findById(weichatBind.getUserId());
//完成模拟登陆,重定向到主页面即可
autoLogin(request,response,user.getUsername(),state);
} else {
//用户第一次绑定,先去绑定手机号,先把userinfoMap放入session中
request.getSession().setAttribute("userinfoMap", userinfoMap);
//重定向到绑定手机号页面
if(state.equals("01")){
//来自PC
response.sendRedirect("http://www.jkgst.com/main.html#!/bind");//去PC页面完成绑定
}else{
//来自移动端
response.sendRedirect("http://www.jkgst.com/m/#!/bind");//去手机页面完成绑定
}
}
}
}
}


2.后端自动登陆

/**
* 后端自动登陆
*
* @param type  PC 或 Mobile
*
* @author simon
* @date 2016/02/26
* */
public void autoLogin(HttpServletRequest request,
HttpServletResponse response,String username,String type)
throws Exception {
ObjectWriter viewWriter = this.mapper.writerWithView(JsonViews.Self.class);
ResponseBean rb = new ResponseBean();
try {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(username, "",userDetails.getAuthorities());
//Authentication authentication = this.authManager.authenticate(authenticationToken);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
/*
* Reload user as password of authentication principal will be null after authorization and
* password is needed for token generation
*/
//          String ip = request.getRemoteAddr();
//          String token = TokenUtils.createToken(userDetails , ip);
try {
UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
LoginLog  ll        = new LoginLog();
ll.setUserId(((User) userDetails).getId());
ll.setIpAddress(request.getRemoteAddr());
ll.setLoginTime(new Date());
ll.setBrowser(userAgent.getBrowser().getName());
ll.setDevice(userAgent.getOperatingSystem().getDeviceType().getName());
loginLogDao.save(ll);
} catch (Exception e) {
logger.error("fail to save login log", e);
e.printStackTrace();
}
//ADD TO SESSION
request.getSession().setAttribute(Constants.Authentication.CURRENT_USER, userDetails);
List<Map> menuList = new ArrayList<Map>();
if (type != null && !"".equals(type)) {
User user=(User) userDetails;
menuList = menuDao.findByUser(user, type);
}
rb.setData(MapUtils.asMap(MapUtils.any("user", userDetails), MapUtils.any("menus", menuList)));//MapUtils.any("token", token),
String  userinfo   =   URLEncoder.encode(viewWriter.writeValueAsString(userDetails),   "utf-8");
Cookie cookie=new Cookie("user",userinfo);
cookie.setPath("/");
response.addCookie(cookie);

} catch (Exception e) {
logger.error("faile to login", e);
rb.setMessage(100001, "username or password is invalid.");
}finally {
rb.setData(true);
response.getWriter().print(rb);//返回响应信息
}
}


3.读取用户的微信绑定状态

/**
* 读取用户的微信绑定状态
*
* @author simon
* @date 2016/02/25
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("weichatState")
public ResponseBean weichatState() {
ResponseBean responseBean = new ResponseBean();
try{
//根据当前登陆的用户id找到对应的绑定表的信息
WeichatBind weichatBind = userService.getByUserId(LuoboAppContext.currentUser().getId());
if(weichatBind!=null)
responseBean.setData(weichatBind);
else
responseBean.setErrorCode(-1);
}catch (Exception e){
responseBean.setErrorCode(-1);
}
return responseBean;
}


4.用户取消绑定微信号

/**
* 用户取消绑定微信号
*
* @author simon
* @date   2016/02/25
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("unbind")
public ResponseBean UnBindWeixin() {
ResponseBean responseBean = new ResponseBean();
//根据当前登陆的用户id找到对应的绑定表的信息
try {
WeichatBind weichatBind = userService.getByUserId(LuoboAppContext.currentUser().getId());
userService.removeBind(weichatBind.getId());
}catch (Exception e){
responseBean.setErrorCode(-1);
}
return responseBean;
}


5.用户绑定手机号

/**
* @描述  用户绑定手机号
*
* @param mobileNo 绑定的手机号
* @param type     PC 或 Mobile
*
* @author simon
* @date 2016/02/29
*/
@GET
@Path("bind")
public void BindWeixin(@QueryParam("mobileNo") Long mobileNo,
@Context HttpServletRequest request,
@Context HttpServletResponse response,
@QueryParam("type") String type) throws  Exception {
//1.根据要绑定的手机号信息找对应的user信息
User user = userService.getUserByMobileNo(mobileNo);
//2.从session获得在上一步中放入
Map<String, Object> userinfoMap = (Map<String, Object>)request.getSession().getAttribute("userinfoMap");
if(userinfoMap==null){
ResponseBean responseBean=new ResponseBean();
responseBean.setErrorCode(-2);
response.getWriter().print(responseBean);//出现异常
return;
}
if(user==null){//用户不存在,要生成账号
User newuser=new User();
newuser.setMobileNo(mobileNo);
newuser.setName(userinfoMap.get("nickname").toString());
newuser.setEnabled(true);
newuser.setStatus("1");
if(type.equals("PC")){
newuser.setRegDevice("01");
}else{
newuser.setRegDevice("02");
}
newuser.setUsername(""+mobileNo);
String password=CodeUtils.generateRandomString(6);//随机密码
newuser.setPassword(this.passwordEncoder.encode(password));
newuser.addRole(Constants.Role.USER);
user= this.userDao.save(newuser);//生成账号
//微信登陆注册成功计算获得积分
try {
int obtainPoints = pointsService.calculatePointsForUserRegister(user.getId());
} catch (Exception e) {
logger.error("error occurs: ", e);
// 记录错误日志
}
// 注册成功的同时,新增一个对应的简历记录
MicroCv cv = new MicroCv();
cv.setUserId(user.getId());
cv.setName(user.getName());
cv.setPhone(user.getMobileNo());
cv.setEmail(user.getEmail());
cv.setIsSelf(true);
microCvDao.save(cv);
//注册成功的同时,要新增一个对应的积分记录
//如果注册时带了邀请码,则给邀请人加积分
//          if (!StringUtils.isEmpty(bean.getToken())) {
//                try {
//                    pointsService.calculatePointsForInviteRegister(bean.getToken(), user.getName(), String.valueOf(user.getMobileNo()));
//                } catch (Exception e) {
//                    logger.error("error occurs: ", e);
//                    // 记录错误日志
//                }
//           }
WeichatBind weichatBind = new WeichatBind();
weichatBind.setUnionid(userinfoMap.get("unionid").toString());
weichatBind.setUserId(user.getId());
//完成绑定
WeichatBind weichatBind1=userService.createBind(weichatBind);
//完成模拟登陆
autoLogin(request,response,user.getUsername(),type);
}else{
//已经存在,找到账号完成绑定,再模拟登陆
WeichatBind weichatBind = new WeichatBind();
weichatBind.setUnionid(userinfoMap.get("unionid").toString());
weichatBind.setUserId(user.getId());
WeichatBind weichatBind1=userService.createBind(weichatBind);//3.完成绑定
//完成模拟登陆
if(type.equals("PC")){
autoLogin(request,response,user.getUsername(),"PC");
}else{
autoLogin(request,response,user.getUsername(),null);
}
}
}


6.与微信平台交互的代码

package com.bigluobo.utils;

import com.google.gson.*;
import com.google.gson.reflect.TypeToken;

import java.io.*;
import java.net.*;
import java.util.*;

/**
* Created by Henry on 2015/12/15.
*/
public class CodeUtils {
private  static  final  String   appid="******************";
private  static  final  String   secret="******************";

//获得随机值
public static final String generateRandomString(int length) {
String allChar = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
StringBuffer sb = new StringBuffer();
Random random = new Random();
for (int i = 0; i < length; i++) {
sb.append(allChar.charAt(random.nextInt(allChar.length())));
}
return sb.toString();
}

/**
* 通过code向微信开放平台请求access_token
*
* @param code
*
*/
public static Map<String,Object>  get_access_token(String code) {
//拼接请求access_token的链接
String url = "https://api.weixin.qq.com/sns/oauth2/access_token";

String params="appid="+appid+"&secret="+secret+"&code="+
code+"&grant_type=authorization_code";

String resultJson = sendGet(url, params);
Map<String,Object> map = parseData(resultJson);//将返回的json数据转换为Map结构存储
/*示例:
*{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE",
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
* */
return map;
}
/**
* 函数名称: refresh_access_token
*
* 函数描述: access_token超时,使用refresh_token重新获得一个access_token
*
* @param   refresh_token
* @return  Map<String, String>
*/
public static Map<String,Object> refresh_access_token(String refresh_token){
//access_token超时,此时需要重新获得一个access_token。
String url_access="https://api.weixin.qq.com/sns/oauth2/refresh_token";

StringBuffer params_access=new StringBuffer()
.append("appid=").append(appid)
.append("&grant_type=refresh_token")
.append("&refresh_token=").append(refresh_token);
String resultJson=sendGet(url_access,params_access.toString());
Map<String,Object> map = parseData(resultJson);//将返回的json数据转换为Map结构存储
/*
* {
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE"
}
* */
return map;
}

/**
* 函数名称: get_userinfo
*
* 函数描述: 通过access_token去获取用户的信息
*
* @param   access_token
* @return  Map<String, String>
*/
public static Map<String,Object> get_userinfo(String access_token,String openid){
//access_token超时,此时需要重新获得一个access_token。
String url_userinfo="https://api.weixin.qq.com/sns/userinfo";
StringBuffer params_userinfo=new StringBuffer()
.append("access_token=").append(access_token)
.append("&openid=").append(openid);
String resultJson=sendGet(url_userinfo,params_userinfo.toString());
Map<String,Object> map = parseData(resultJson);//将返回的json数据转换为Map结构存储
if(map.size()>3){
//已经正确获取到用户信息
/*
* {
"openid":"OPENID",
"nickname":"NICKNAME",
"sex":1,
"province":"PROVINCE",
"city":"CITY",
"country":"COUNTRY",
"headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
"privilege":[
"PRIVILEGE1",
"PRIVILEGE2"
],
"unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
* */
return map;
}else{
if(map.get("errcode").equals("42001")){
//access_token超时,需要重新获得access_token超时,再请求用户信息
Map<String,Object> map1= refresh_access_token(access_token);
String access_token2=map1.get("access_token").toString();
String openid2=map1.get("openid").toString();
//刷新以后重新获取用户的信息
get_userinfo(access_token2,openid2);
}
}
return map;
}

/**
* 函数名称: parseData
* 函数描述: 将json字符串转换为Map<String, String>结构
*
* @param   data
* @return  Map<String, String>
*/
private static Map<String, Object> parseData(String data) {
GsonBuilder gb = new GsonBuilder();
Gson g = gb.create();
Map<String, Object> map = g.fromJson(data, new TypeToken<Map<String, Object>>() {
}.getType());
return map;
}

/**
* 向指定URL发送GET方法的请求
*
* @param url   发送请求的URL
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return URL 所代表远程资源的响应结果
*/
public static String sendGet(String url, String param) {
String result = "";
BufferedReader in = null;
try {
String urlNameString = url + "?" + param;
URL realUrl = new URL(urlNameString);
// 打开和URL之间的连接
URLConnection connection = realUrl.openConnection();
// 设置通用的请求属性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 建立实际的连接
connection.connect();
// 获取所有响应头字段
Map<String, List<String>> map = connection.getHeaderFields();

// 定义 BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送GET请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: