java实现⼩程序登录授权(第1版_city)
需要的材料
1:⼀个可以测试的⼩程序
2:此⼩程序的APPID和APP_SECRET
⼩程序⽤户表
CREATE TABLE`wx_user`(
`id`int(20)NOT NULL AUTO_INCREMENT,
`openid`varchar(28)DEFAULT NULL COMMENT'⼩程序的openid',
`nick_name`varchar(100)DEFAULT NULL COMMENT'昵称',
`real_name`varchar(100)DEFAULT NULL COMMENT'姓名',
`headimg_url`varchar(100)DEFAULT NULL COMMENT'头像',
`gender`tinyint(1)DEFAULT NULL COMMENT'性别  0-男、1-⼥',
`country`varchar(100)DEFAULT NULL COMMENT'所在国家',
`province`varchar(100)DEFAULT NULL COMMENT'省份',
`city`varchar(100)DEFAULT NULL COMMENT'城市',
`language`varchar(100)DEFAULT NULL COMMENT'语种',
`mobile`varchar(50)DEFAULT NULL COMMENT'⼿机号码',
`create_time`datetime DEFAULT NULL COMMENT'创建时间',
`update_time`datetime DEFAULT NULL COMMENT'更新时间',
`login_time`datetime DEFAULT NULL COMMENT'登录时间',
PRIMARY KEY(`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='⼩程序⽤户表';
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.47</version>
</dependency>
Controller
ller;
import com.alibaba.fastjson.JSONObject;
startalk_yytmon.R;
startalk_yyt.service.WeChatLoginAuthService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apachemons.lang3.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Arrays;
import org.ders.Base64;
pto.Cipher;
pto.spec.IvParameterSpec;
pto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.security.Security;
import java.util.Map;
@Api(tags ="登录授权")
@RestController
@RequestMapping("wechat")
public class WeChatLoginAuthController {
@Autowired
WeChatLoginAuthService weChatLoginAuthService;
@ApiOperation("登录凭证校验。获取到 code 后传到开发者服务器调⽤此接⼝完成登录流程")
@PostMapping("/getCode2Session")
public R getCode2Session(@ApiParam(value ="{'code':''}")@RequestBody Map<String, String> params){ if(!ainsKey("code")|| StringUtils.("code"))){
("临时登录凭证code不能为空");
}
String code = ("code");有趣的java小程序
// 调⽤业务层的⽅法处理业务
Code2Session(code);
}
@ApiOperation(value ="解密密⽂获取⼿机号")
@PostMapping("/parsedata")
public R parseData(
@ApiParam(value ="{\"encrypted\":\"加密数据\",\"iv\":\"初始向量\",\"sessionKey\":\"解密的key\"}")
@RequestBody Map<String, Object> params){
if(!ainsKey("encrypted")||!ainsKey("iv")||!ainsKey("sessionKey")){ ("必要参数缺失");
}
Object iv = ("iv");
Object encrypted = ("encrypted");
Object sessionKey = ("sessionKey");
// 解密数据encryptedData
String userInfo =String(), String(), iv.toString());
if(StringUtils.isNotBlank(userInfo)){
Map map = JSONObject.parseObject(userInfo, Map.class);
System.out.println("data ==== "+ map);
return R.ok().put("data", map);
}
("解密数据失败");
}
/**
* ⼩程序解密⽤户敏感数据获取⽤户信息
*
* @param encryptedData 包括敏感数据在内的完整⽤户信息的加密数据
* @param sessionKey    数据进⾏加密签名的密钥
* @param iv            加密算法的初始向量
* @return
*/
public String getUserInfo(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 +(keyByte.length % base !=0?1:0);
byte[] temp =new byte[groups * base];
Arrays.fill(temp,(byte)0);
System.arraycopy(keyByte,0, temp,0, keyByte.length);
keyByte = temp;
}
// 初始化
Security.addProvider(new BouncyCastleProvider());
Security.addProvider(new BouncyCastleProvider());
Cipher cipher = Instance("AES/CBC/PKCS7Padding","BC");
SecretKeySpec spec =new SecretKeySpec(keyByte,"AES");
AlgorithmParameters parameters = Instance("AES");            parameters.init(new IvParameterSpec(ivByte));
cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化byte[] resultByte = cipher.doFinal(dataByte);
if(null != resultByte && resultByte.length >0){
return new String(resultByte,"UTF-8");
}
}catch(Exception e){
e.printStackTrace();
}
return null;
}
}
Service
startalk_yyt.service;
startalk_yytmon.R;
public interface WeChatLoginAuthService {
R getCode2Session(String code);
}
impl
startalk_yyt.service.impl;
import com.alibaba.fastjson.JSON;
startalk_yytmon.HttpClientUtil;
startalk_yytmon.R;
startalk_yytmon.WeChatConstant;
startalk_yyt.service.WeChatLoginAuthService;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
public class WeChatLoginAuthServiceImpl implements WeChatLoginAuthService {
@Override
public R getCode2Session(String code){
String result ="";
String url = WeChatConstant.CODE2_SESSION;
url = place("APPID", WeChatConstant.APPID)
.replace("SECRET", WeChatConstant.APP_SECRET)
.replace("JSCODE", code);
String doGet = HttpClientUtil.doGet(url);
Map map = JSON.parseObject(doGet, Map.class);
ainsKey("errcode")){
result = String.("errmsg"));
}else{
String openid = String.("openid"));// ⽤户唯⼀标识
//⽤户在开放平台的唯⼀标识符,在满⾜ UnionID 下发条件的情况下会返回
String sessionKey = String.("session_key"));
Map<Object, Object> code2Session =new HashMap<>(2);
code2Session.put("openid", openid);
code2Session.put("sessionKey", sessionKey);
return R.ok().put("data", code2Session);
}
(result);
}
}
常量类
startalk_yytmon;
public class WeChatConstant {
// ⼩程序相关的配置
// ID和密钥
public static final String APPID ="89e4a04";
public static final String APP_SECRET ="d13d622d3151e";
/
/ 获取⼩程序全局唯⼀后台接⼝调⽤凭据(access_token)  GET
public static final String ACCESS_TOKEN ="api.weixin.qq/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"; // 登录凭证校验。通过 wx.login 接⼝获得临时登录凭证 code 后传到开发者服务器调⽤此接⼝完成登录流程  GET
public static final String CODE2_SESSION ="api.weixin.qq/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_ty pe=authorization_code";
}
HttpClientUtil
startalk_yytmon;
import org.apache.http.NameValuePair;
import org.apache.ity.UrlEncodedFormEntity;
import org.apache.hods.CloseableHttpResponse;
import org.apache.hods.HttpGet;
import org.apache.hods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.ity.ContentType;
import org.ity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.ssage.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 基于 HttpClient ⼯具的请求
*/
public class HttpClientUtil {
public static String doGet(String url){
return doGet(url, null);
}
public static String doPost(String url){
return doPost(url, null);
}
public static String doGet(String url, Map<String, Object> param){
// 创建Httpclient对象
CloseableHttpClient httpclient = ateDefault();
String resultString ="";
CloseableHttpResponse response = null;
try{
// 创建uri
URIBuilder builder =new URIBuilder(url);
if(param != null){
for(String key : param.keySet()){
builder.addParameter(key, String.(key)));
}
}
URI uri = builder.build();
// 创建http GET请求
HttpGet httpGet =new HttpGet(uri);
// 执⾏请求
response = ute(httpGet);
// 判断返回状态是否为200
StatusLine().getStatusCode()==200){
resultString = Entity(),"UTF-8");
}
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(response != null){
response.close();
}
httpclient.close();
}catch(IOException e){
e.printStackTrace();
}
}