1. 程式人生 > 其它 >微信授權並登陸

微信授權並登陸

技術標籤:微信授權java

微信授權並登陸

記錄自己第一次寫微信授權後的成果,以便後續查詢學習。
參考文件:

https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html

1. 先確認接收的引數

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=
STATE#wechat_redirect

授權會呼叫這個網址,使用者同意授權後重定向到redirect_uri(即為後臺授權的介面路徑)處,後臺可以接收到兩個引數:code和state;通過code可以獲取使用者openid,state中可以存放自己需要的引數,也可以不存,通過下方方式獲取:

String code = request.getParameter("code");
String appid = request.getParameter("state");

在這裡因為我的appid需要動態獲取,所以把appid放在了state中。

2. 通過code換取網頁授權access_token

網址:https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

引數:appId
	 secret
	 code

通過get請求呼叫這個網址後得到JSONObject物件,可以得到access_token和openid:

WeiXinOauth2Token weiXinOauth2Token = new WeiXinOauth2Token();
weiXinOauth2Token.setAccessToken
(jsonObject.getString("access_token"));//網頁授權介面呼叫憑證 weiXinOauth2Token.setExpiresIn(jsonObject.getInt("expires_in"));//access_token介面呼叫憑證超時時間,單位(秒) weiXinOauth2Token.setRefreshToken(jsonObject.getString("refresh_token"));//使用者重新整理access_token weiXinOauth2Token.setOpenId(jsonObject.getString("openid"));//使用者唯一標識 weiXinOauth2Token.setScope(jsonObject.getString("scope"));//使用者授權的作用域,使用逗號(,)分隔

3. 根據accessToken openid 獲得使用者資訊

網址:https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID

引數:access_token
	 openid

通過get請求呼叫這個網址後得到JSONObject物件,可以得到使用者的基本資訊:

WeChatUser weChatUser =new WeChatUser();
weChatUser.setOpenid(jsonObject.getString("openid"));//使用者的唯一標識
weChatUser.setNickName(jsonObject.getString("nickname"));//使用者暱稱
weChatUser.setSex(jsonObject.getString("sex"));//使用者的性別,值為1時是男性,值為2時是女性,值為0時是未知
weChatUser.setProvince(jsonObject.getString("province"));//使用者個人資料填寫的省份
weChatUser.setCity(jsonObject.getString("city"));//普通使用者個人資料填寫的城市
if (jsonObject.getString("headimgurl") != null
		&& !jsonObject.getString("headimgurl").toString().trim().equals("")) {//使用者頭像
	weChatUser.setHeadImgUrl(jsonObject.getString("headimgurl"));
} else {
    weChatUser.setHeadImgUrl("");
}
StringBuffer privilege = null;//使用者特權資訊,json 陣列,這裡為了方便寫成了String型別的
List<String> privilegeList = JSONArray.toList(jsonObject.getJSONArray("privilege"), List.class);
for (int i = 0; i < privilegeList.size();i ++) {
    if (i != privilegeList.size() - 1) {
          privilege.append(privilegeList.get(i)+",");
    } else {
          privilege.append(privilegeList.get(i));
    }
}
weChatUser.setPrivilege(privilege.toString());
if (jsonObject.get("unionid") != null) {//只有在使用者將公眾號繫結到微信開放平臺帳號後,才會出現該欄位
    weChatUser.setUnionId(jsonObject.getString("unionid"));
}

4. 登陸

使用者授權獲取使用者基本資訊後儲存到使用者表,生成使用者的使用者名稱和密碼:

sysUser.setUsername(weChatUser.getNickName());
String salt = oConvertUtils.randomGen(8);
sysUser.setSalt(salt);
String passwordEncode = PasswordUtil.encrypt(sysUser.getUsername(), weChatUser.getOpenid().substring(weChatUser.getOpenid().length() - 6, weChatUser.getOpenid().length()) + "123456&", salt);
sysUser.setPassword(passwordEncode);

根據使用者名稱和密碼產生token,存到redis中,然後重定向到首頁:

String password = sysUser.getPassword();
String username = sysUser.getUsername();
// 生成token
String token = JwtUtil.sign(username,password);
redisUtil.set("openID" + token, sysUser.getOpenId());
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
// 設定超時時間
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 1000);
redisUtil.expire("openID" + token, JwtUtil.EXPIRE_TIME / 1000);
// 重定向到首頁
response.sendRedirect("");

附:全部後端程式碼

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.util.PasswordUtil;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.business.entity.WeChatUser;
import org.jeecg.modules.system.entity.SysUser;

import org.jeecg.modules.system.service.ISysUserService;
import org.jeecg.modules.weixin.entity.ZzInstitutionGzhInfo;
import org.jeecg.modules.weixin.service.IZzInstitutionGzhInfoService;
import org.jeecg.modules.weixin.service.WxTokenService;
import org.jeecg.modules.weixin.vo.WeiXinOauth2Token;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@RestController
@RequestMapping("/weixin")
@Api(tags = "微信介面")
@Slf4j
public class WeiXinUserController {

    @Autowired
    private IZzInstitutionGzhInfoService zzInstitutionGzhInfoService;
    @Autowired
    private WxTokenService wxTokenService;
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private RedisUtil redisUtil;


    @RequestMapping(value = "/wxAuthorize", method = RequestMethod.GET)
    @ApiOperation("微信授權獲取使用者資訊並登陸")
    public Result<WeChatUser> wxAuthorize(HttpServletRequest request, HttpServletResponse response) {
        Result<WeChatUser> result = new Result<>();
        try {
            String code = request.getParameter("code");
            String appid = request.getParameter("state");
            log.info("========appid="+appid);
            WeiXinOauth2Token weiXinOauth2Token = null;
            if (StringUtils.isNotBlank(code)) {
                // state中儲存的是appid,根據appid去表中查詢該機構的secret
                // 此處是因為我的appid和secret需要動態獲取,所以進行查詢,如果不需要動態獲取可以省略此步驟
                ZzInstitutionGzhInfo zzInstitutionGzhInfo = zzInstitutionGzhInfoService.getInstitutionGzhInfo(appid);
                // 根據 appid secret code 獲取openid
                weiXinOauth2Token = wxTokenService.getOauth2AccessToken(appid, zzInstitutionGzhInfo.getAppSecret(), code);
                log.info("========weiXinOauth2Token{}",weiXinOauth2Token);
                if (weiXinOauth2Token != null) {
                    String accessToken = weiXinOauth2Token.getAccessToken();
                    log.info("==========accessToken="+accessToken);
                    String openid = weiXinOauth2Token.getOpenId();
                    // 根據accessToken openid 獲得使用者資訊
                    WeChatUser weChatUser = wxTokenService.getSNSUserInfo(accessToken, openid);
                    // 授權後登陸
                    SysUser sysUser = sysUserService.getUserByOpenId(openid);
                    if (sysUser == null) {
                     	// 儲存使用者的基本資訊
                        sysUser = new SysUser();
                        sysUser.setOpenId(weChatUser.getOpenid());
                        sysUser.setNickname(weChatUser.getNickName());
                        sysUser.setSex(Integer.valueOf(weChatUser.getSex()));
                        sysUser.setProvince(weChatUser.getProvince());
                        sysUser.setCity(weChatUser.getCity());
                        sysUser.setHeadImgUrl(weChatUser.getHeadImgUrl());
                        sysUser.setPrivilege(weChatUser.getPrivilege());
                        sysUser.setUnionid(weChatUser.getUnionId());
                        sysUser.setUsername(weChatUser.getNickName());
                        // 生成使用者登入的加鹽密碼
                        // 可以根據自己需要生成密碼,這裡就不再展示
                        String salt = oConvertUtils.randomGen(8);
                        sysUser.setSalt(salt);
                        String passwordEncode = PasswordUtil.encrypt(sysUser.getUsername(), weChatUser.getOpenid().substring(weChatUser.getOpenid().length() - 6, weChatUser.getOpenid().length()) + "123456&", salt);
                        sysUser.setPassword(passwordEncode);
                        sysUserService.save(sysUser);
                    }
                    String password = sysUser.getPassword();
                    String username = sysUser.getUsername();
                    // 根據使用者名稱和密碼生成token
                    String token = JwtUtil.sign(username,password);
                    redisUtil.set("appId"+token,appid);
                    redisUtil.set("openID" + token, sysUser.getOpenId());
                    redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
                    // 設定超時時間
                    redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 1000);
                    redisUtil.expire("openID" + token, JwtUtil.EXPIRE_TIME / 1000);
                    // 重定向到首頁
                    response.sendRedirect("");
                    // 這裡返回資料是因為前臺需要,如果不需要可以不寫
                    result.setResult(weChatUser);
                    result.success("微信授權獲取使用者資訊並登陸成功");
                    return result;
                } else {
                    result.setMessage("微信授權獲取使用者資訊並登陸 獲取token為空");
                    return result;
                }
            } else {
                result.setMessage("微信授權失敗");
                return result;
            }
        } catch (Exception e) {
            log.error("微信授權登入失敗", e.getMessage());
        }
        return result;
    }
}
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONArray;
import org.jeecg.modules.business.entity.WeChatUser;
import org.jeecg.modules.weixin.service.WxTokenService;
import org.jeecg.modules.weixin.utils.HttpsX509TrustManager;
import org.jeecg.modules.weixin.vo.WeiXinOauth2Token;
import org.springframework.stereotype.Service;
import net.sf.json.JSONObject;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.URL;
import java.security.SecureRandom;
import java.util.List;

@Service
@Slf4j
public class WxTokenServiceImpl implements WxTokenService {

    /**
     * 網頁授權獲取openid
     * @param appId
     * @param appSecret
     * @param code
     * @return
     */
    @Override
    public WeiXinOauth2Token getOauth2AccessToken(String appId, String appSecret, String code) {
        WeiXinOauth2Token weiXinOauth2Token = null;
        String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
        requestUrl = requestUrl.replace("APPID", appId);
        requestUrl = requestUrl.replace("SECRET", appSecret);
        requestUrl = requestUrl.replace("CODE", code);

        JSONObject jsonObject = httpsRequest(requestUrl, "GET", null);
        if (jsonObject != null) {
            try {
                weiXinOauth2Token = new WeiXinOauth2Token();
                weiXinOauth2Token.setAccessToken(jsonObject.getString("access_token"));
                weiXinOauth2Token.setExpiresIn(jsonObject.getInt("expires_in"));
                weiXinOauth2Token.setRefreshToken(jsonObject.getString("refresh_token"));
                weiXinOauth2Token.setOpenId(jsonObject.getString("openid"));
                weiXinOauth2Token.setScope(jsonObject.getString("scope"));
            } catch (Exception e) {
                weiXinOauth2Token = null;
                int errorCode = jsonObject.getInt("errcode");
                String str1 = jsonObject.getString("errmsg");
                log.error(e.getMessage());
            }
        }
        return weiXinOauth2Token;
    }

    private JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {
        JSONObject jsonObject = null;
        try {
            TrustManager[] tm = {new HttpsX509TrustManager()};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new SecureRandom());

            SSLSocketFactory ssf = sslContext.getSocketFactory();

            URL url = new URL(requestUrl);
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
            conn.setSSLSocketFactory(ssf);

            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);

            conn.setRequestMethod(requestMethod);
            if (outputStr != null) {
                OutputStream outputStream = conn.getOutputStream();

                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }
            InputStream inputStream = conn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            StringBuffer buffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            inputStream = null;
            conn.disconnect();
            jsonObject = JSONObject.fromObject(buffer.toString());
        } catch (ConnectException localConnectException) {
        } catch (Exception localException) {
        }
        return jsonObject;
    }

    /**
     * 網頁授權獲取使用者資訊
     * @param accessToken
     * @param openId
     * @return
     */
    @Override
    public WeChatUser getSNSUserInfo(String accessToken, String openId) {
        WeChatUser weChatUser = null;
        String requestUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";
        requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);
        JSONObject jsonObject = httpsRequest(requestUrl,"GET",null);
        log.info("=============jsonObject="+jsonObject);
        if (jsonObject.getString("errcode") != null) {
        } else {
            weChatUser =new WeChatUser();
            weChatUser.setOpenid(jsonObject.getString("openid"));
            weChatUser.setNickName(jsonObject.getString("nickname"));
            weChatUser.setSex(jsonObject.getString("sex"));
            weChatUser.setProvince(jsonObject.getString("province"));
            weChatUser.setCity(jsonObject.getString("city"));
            if (jsonObject.getString("headimgurl") != null
                    && !jsonObject.getString("headimgurl").toString().trim().equals("")) {
                weChatUser.setHeadImgUrl(jsonObject.getString("headimgurl"));
            } else {
                weChatUser.setHeadImgUrl("");
            }
            StringBuffer privilege = null;
            List<String> privilegeList = JSONArray.toList(jsonObject.getJSONArray("privilege"), List.class);
            for (int i = 0; i < privilegeList.size();i ++) {
                if (i != privilegeList.size() - 1) {
                    privilege.append(privilegeList.get(i)+",");
                } else {
                    privilege.append(privilegeList.get(i));
                }
            }
            weChatUser.setPrivilege(privilege.toString());
            if (jsonObject.get("unionid") != null) {
                weChatUser.setUnionId(jsonObject.getString("unionid"));
            }
            weChatUser.setIsEnabled("1");
        }
        return weChatUser;
    }

}