需求说明:
用户通过小程序登录,进入到平台系统,进行各功能操作;
解决方案:
首先通过对接小程序,用户通过小程序登录及授权获取用户信息,后端调用接口获取微信用户信息,进行保存到数据库,然后返回token给前端(实际在这里相当于用户的一个注册及登录),前端使用该token访问所有接口;
相关代码:
首先我们需要用到 http工具类 方便后续的接口调用:
importorg.apache.http.NameValuePair;importorg.apache.http.client.config.RequestConfig;importorg.apache.http.client.entity.UrlEncodedFormEntity;importorg.apache.http.client.methods.CloseableHttpResponse;importorg.apache.http.client.methods.HttpPost;importorg.apache.http.impl.client.CloseableHttpClient;importorg.apache.http.impl.client.HttpClients;importorg.apache.http.message.BasicNameValuePair;importorg.apache.http.util.EntityUtils;importjava.io.IOException;importjava.util.ArrayList;importjava.util.List;importjava.util.Map;publicclassHttpClientUtils{finalstaticint TIMEOUT =1000;finalstaticint TIMEOUT_MSEC =5*1000;publicstaticStringdoPost(String url,Map<String,String> paramMap)throwsIOException{// 创建Httpclient对象CloseableHttpClient httpClient =HttpClients.createDefault();CloseableHttpResponse response =null;String resultString ="";try{// 创建Http Post请求HttpPost httpPost =newHttpPost(url);// 创建参数列表if(paramMap !=null){List<NameValuePair> paramList =newArrayList<>();for(Map.Entry<String,String> param : paramMap.entrySet()){
paramList.add(newBasicNameValuePair(param.getKey(), param.getValue()));}// 模拟表单UrlEncodedFormEntity entity =newUrlEncodedFormEntity(paramList);
httpPost.setEntity(entity);}
httpPost.setConfig(builderRequestConfig());// 执行http请求
response = httpClient.execute(httpPost);
resultString =EntityUtils.toString(response.getEntity(),"UTF-8");}catch(Exception e){throw e;}finally{try{
response.close();}catch(IOException e){throw e;}}return resultString;}privatestaticRequestConfigbuilderRequestConfig(){returnRequestConfig.custom().setConnectTimeout(TIMEOUT_MSEC).setConnectionRequestTimeout(TIMEOUT_MSEC).setSocketTimeout(TIMEOUT_MSEC).build();}}
小程序用户表
CREATETABLE`wechat_user`(`id`int(11)unsignedNOTNULLAUTO_INCREMENT,`nickname`varchar(100)DEFAULTNULLCOMMENT'用户昵称',`avatar_url`varchar(500)DEFAULTNULLCOMMENT'用户头像',`gender`int(11)DEFAULTNULLCOMMENT'性别 0-未知、1-男性、2-女性',`country`varchar(100)DEFAULTNULLCOMMENT'所在国家',`province`varchar(100)DEFAULTNULLCOMMENT'省份',`city`varchar(100)DEFAULTNULLCOMMENT'城市',`mobile`varchar(100)DEFAULTNULLCOMMENT'手机号码',`open_id`varchar(100)NOTNULLCOMMENT'小程序openId',`union_id`varchar(100)DEFAULT''COMMENT'小程序unionId',`created_at`timestampNOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'插入时间',`updated_at`timestampNOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMPCOMMENT'更新时间',PRIMARYKEY(`id`),KEY`idx_open_id`(`open_id`),KEY`idx_union_id`(`union_id`),KEY`idx_mobile`(`mobile`))ENGINE=InnoDBAUTO_INCREMENT=2DEFAULTCHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='小程序用户表';
dto
importio.swagger.annotations.ApiModelProperty;importlombok.Data;importjavax.validation.constraints.NotNull;@DatapublicclassWechatLoginRequest{//登录时获取的 code,可通过wx.login获取@NotNull(message ="code不能为空")@ApiModelProperty(value ="微信code", required =true)privateString code;//这个入参其实里面包含了用户的信息 下面的impl层 就是解析这个json获取用户信息@ApiModelProperty(value ="用户非敏感字段")privateString rawData;@ApiModelProperty(value ="签名")privateString signature;@ApiModelProperty(value ="用户敏感字段")privateString encryptedData;@ApiModelProperty(value ="解密向量")privateString iv;}
主要代码:
controller
importio.swagger.annotations.Api;importio.swagger.annotations.ApiOperation;importlombok.extern.slf4j.Slf4j;importorg.springframework.validation.annotation.Validated;importorg.springframework.web.bind.annotation.PostMapping;importorg.springframework.web.bind.annotation.RequestBody;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjavax.annotation.Resource;@RestController@RequestMapping("/wechat")@Api(tags ={"微信小程序"}, value ="/wechat")@Slf4jpublicclassLoginController{@ResourceprivateWechatService wechatService;@ApiOperation(value ="登入接口", httpMethod ="POST")@PostMapping("/login")publicResponseResultlogin(@Validated@RequestBodyWechatLoginRequest loginRequest)throwsException{return wechatService.getUserInfoMap(loginRequest);}}
mapper
importcom.baomidou.mybatisplus.core.mapper.BaseMapper;importcom.mmc.aircraftsystemserver.api.wechet.pojo.WechatUser;importorg.apache.ibatis.annotations.Mapper;@MapperpublicinterfaceWechatMapperextendsBaseMapper<WechatUser>{}
impl
packagecom.mmc.aircraftsystemserver.api.wechet.service.impl;importcn.hutool.core.codec.Base64;importcom.alibaba.fastjson.JSON;importcom.alibaba.fastjson.JSONObject;importcom.baomidou.mybatisplus.core.conditions.query.QueryWrapper;importcom.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;importcom.baomidou.mybatisplus.extension.service.impl.ServiceImpl;importlombok.extern.slf4j.Slf4j;importorg.apache.commons.codec.digest.DigestUtils;importorg.apache.commons.lang3.StringUtils;importorg.bouncycastle.jce.provider.BouncyCastleProvider;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.data.redis.core.StringRedisTemplate;importorg.springframework.stereotype.Service;importjavax.crypto.Cipher;importjavax.crypto.spec.IvParameterSpec;importjavax.crypto.spec.SecretKeySpec;importjava.security.AlgorithmParameters;importjava.security.Security;importjava.util.Arrays;importjava.util.HashMap;importjava.util.Map;importjava.util.concurrent.TimeUnit;@Slf4j@ServicepublicclassWechatServiceImplextendsServiceImpl<WechatMapper,WechatUser>implementsWechatService{//小程序 appId@Value("${wechat.appid}")privateString APPID;//小程序 appSecret@Value("${wechat.secret}")privateString SECRET;//${wechat.grantType} = authorization_code@Value("${wechat.grantType}")privateString GRANT_TYPE;// ${wechat.url} = https://api.weixin.qq.com/sns/jscode2session@Value("${wechat.url}")privateString REQUEST_URL;publicResponseResultgetUserInfoMap(WechatLoginRequest loginRequest)throwsException{JSONObject sessionKeyOpenId =getSessionKeyOrOpenId(loginRequest.getCode());// 获取openId && sessionKeyString openId = sessionKeyOpenId.getString("openid");String sessionKey = sessionKeyOpenId.getString("session_key");//校验签名 小程序发送的签名signature与服务器端生成的签名signature2 = sha1(rawData + sessionKey)String signature2 =DigestUtils.sha1Hex(loginRequest.getRawData()+ sessionKey);if(!loginRequest.getSignature().equals(signature2)){returnResponseResult.errorResult(HttpCodeEnum.FAIL,"签名校验失败");}WechatUser insertOrUpdateDO =buildWechatUserAuthInfoDO(loginRequest, sessionKey, openId);// 根据code保存openId和sessionKeyJSONObject sessionObj =newJSONObject();
sessionObj.put("openId", openId);
sessionObj.put("sessionKey", sessionKey);// 根据openid查询用户QueryWrapper wrapper =newQueryWrapper();
wrapper.eq("open_id",openId);WechatUser user =getOne(wrapper);if(user ==null){// 用户不存在,insert用户save(insertOrUpdateDO);}else{// 已存在,更新用户的信息UpdateWrapper<WechatUser> updateWrapper =newUpdateWrapper();
updateWrapper.eq("openId",openId).set("nickname",insertOrUpdateDO.getNickname()).set("avatar_url",insertOrUpdateDO.getAvatarUrl()).set("gender",insertOrUpdateDO.getGender()).set("country",insertOrUpdateDO.getCountry()).set("province",insertOrUpdateDO.getProvince()).set("city",insertOrUpdateDO.getCity()).set("mobile",insertOrUpdateDO.getMobile());update(updateWrapper);}ResponseResult token =createToken(insertOrUpdateDO);returnResponseResult.okResult(token);}//调用接口privateJSONObjectgetSessionKeyOrOpenId(String code)throwsException{Map<String,String> requestUrlParam =newHashMap<>();
requestUrlParam.put("appid", APPID);
requestUrlParam.put("secret", SECRET);
requestUrlParam.put("js_code", code);
requestUrlParam.put("grant_type", GRANT_TYPE);// 发送post请求读取调用微信接口获取openid用户唯一标识String result =HttpClientUtils.doPost(REQUEST_URL, requestUrlParam);return JSON.parseObject(result);}privateWechatUserbuildWechatUserAuthInfoDO(WechatLoginRequest loginRequest,String sessionKey,String openId){WechatUser wechatUserDO =newWechatUser();
wechatUserDO.setOpenId(openId);if(loginRequest.getRawData()!=null){RawDataDO rawDataDO = JSON.parseObject(loginRequest.getRawData(),RawDataDO.class);
wechatUserDO.setNickname(rawDataDO.getNickName());
wechatUserDO.setAvatarUrl(rawDataDO.getAvatarUrl());
wechatUserDO.setGender(rawDataDO.getGender());
wechatUserDO.setCity(rawDataDO.getCity());
wechatUserDO.setCountry(rawDataDO.getCountry());
wechatUserDO.setProvince(rawDataDO.getProvince());}// 解密加密信息,获取unionIDif(loginRequest.getEncryptedData()!=null){JSONObject encryptedData =getEncryptedData(loginRequest.getEncryptedData(), sessionKey, loginRequest.getIv());if(encryptedData !=null){String unionId = encryptedData.getString("unionId");
wechatUserDO.setUnionId(unionId);}}return wechatUserDO;}privateJSONObjectgetEncryptedData(String encryptedData,String sessionkey,String iv){// 被加密的数据byte[] dataByte =Base64.decode(encryptedData);// 加密秘钥byte[] keyByte =Base64.decode(sessionkey);// 偏移量byte[] ivByte =Base64.decode(iv);try{// 如果密钥不足16位,那么就补足.这个if中的内容很重要int base =16;if(keyByte.length % base !=0){int groups = keyByte.length / base +1;byte[] temp =newbyte[groups * base];Arrays.fill(temp,(byte)0);System.arraycopy(keyByte,0, temp,0, keyByte.length);
keyByte = temp;}// 初始化Security.addProvider(newBouncyCastleProvider());Cipher cipher =Cipher.getInstance("AES/CBC/PKCS7Padding","BC");SecretKeySpec spec =newSecretKeySpec(keyByte,"AES");AlgorithmParameters parameters =AlgorithmParameters.getInstance("AES");
parameters.init(newIvParameterSpec(ivByte));
cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化byte[] resultByte = cipher.doFinal(dataByte);if(null!= resultByte && resultByte.length >0){String result =newString(resultByte,"UTF-8");returnJSONObject.parseObject(result);}}catch(Exception e){
log.error("解密加密信息报错", e.getMessage());}returnnull;}//生成token 这里可以忽略 根据自己当前业务系统选取生成方式publicResponseResultcreateToken(WechatUser wechatUser){String openid = wechatUser.getOpenId();String token =MD5Util.getMD5Str(openid +System.currentTimeMillis());String flyingSessionId =MD5Util.getMD5Str("HAHA"+ wechatUser.getOpenId());
wechatUser.getStringRedisTemplate().opsForValue().set(token, wechatUser.getNickname());//外部登录生成tokenString key = token + flyingSessionId;Map<String,String> redisData =newHashMap<>();
redisData.put("HAHA-TOKEN", token);
redisData.put("HAHA-SESSIONID", flyingSessionId);
redisData.put("uid", wechatUser.getId()+"");
redisData.put("openid", wechatUser.getOpenId());
redisData.put("nickname", wechatUser.getNickname());
wechatUser.getStringRedisTemplate().opsForHash().putAll(key, redisData);
wechatUser.getStringRedisTemplate().expire(key,86400,TimeUnit.SECONDS);returnResponseResult.okResult(redisData);}}
注意:
微信小程序更新后:
#### 前端调用接口 参数一次性给齐 这样就可以一次调用 获取所有;
版权归原作者 某_ 所有, 如有侵权,请联系我们删除。