微信授權登陸-app
阿新 • • 發佈:2018-12-18
app介入第三方微信登陸功能:
移動應用微信登入是基於OAuth2.0協議標準 構建的微信OAuth2.0授權登入系統,前提你需要到微信開放平臺註冊開發者帳號,並擁有一個已稽核通過的移動應用,並獲得相應的AppID和AppSecret,申請微信登入且通過稽核後,可開始接入流程。
接入微信登陸授權步驟:
1. 第三方發起微信授權登入請求,微信使用者允許授權第三方應用後,微信會拉起應用或重定向到第三方網站,並且帶上授權臨時票據code引數;
2. 通過code引數加上AppID和AppSecret等,通過API換取access_token;
3. 通過access_token進行介面呼叫,獲取使用者基本資料資源或幫助使用者實現基本操作。
注意:同一個微信開放平臺下繫結的使用者,在不同的應用下使用者的UnionID就是相同的,openId是不相同的。
獲取access_token流程:
第一步:請求CODE:
需要app調起微信
第二步:通過code獲取access_token:
引數:
appid | 是 | 應用唯一標識,在微信開放平臺提交應用稽核通過後獲得 |
secret | 是 | 應用金鑰AppSecret,在微信開放平臺提交應用稽核通過後獲得 |
code | 是 | 填寫第一步獲取的code引數 |
grant_type | 是 | 填authorization_code |
appid與secret需要通過註冊獲取。
第三步:通過access_token呼叫介面
獲取access_token後,進行介面呼叫,有以下前提:
- access_token有效且未超時;
- 微信使用者已授權給第三方應用帳號相應介面作用域(scope)。
程式碼:
請求微信工具類:
package com.maobc.util; import com.alibaba.fastjson.JSONObject; import com.maobc.entity.jar.Member; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.HttpClients; import org.apache.poi.ss.formula.functions.T; import springfox.documentation.spring.web.json.Json; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URI; /** * @program: maobc-small_routine * @description: app使用者登陸 * @author: z.hw **/ public class WeixinLoginUtils { /** * 微信登陸通過code獲取accessToken * @param appId * @param userAppSecret * @param code * @return * @throws Exception */ public StringBuilder getAccessTokenBycode(String appId,String userAppSecret,String code) throws Exception{ //檢視官方文件 https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419317853&token=&lang= String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+appId+"&secret="+ userAppSecret+"&code="+code+"&grant_type=authorization_code"; URI uri = URI.create(url); HttpClient client = HttpClients.createDefault(); HttpGet get = new HttpGet(uri); HttpResponse response=client.execute(get); StringBuilder sb = new StringBuilder(); if (response.getStatusLine().getStatusCode() == 200) { HttpEntity entity = response.getEntity(); BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8")); for (String temp = reader.readLine(); temp != null; temp = reader.readLine()) { sb.append(temp); } } return sb; } /** * access_token是否有效的驗證 * @param accessToken * @param openID * @return */ public boolean isAccessTokenIsInvalid(String accessToken,String openID) throws Exception{ String url = "https://api.weixin.qq.com/sns/auth?access_token=" + accessToken + "&openid=" + openID; URI uri = URI.create(url); HttpClient client = HttpClients.createDefault(); HttpGet get = new HttpGet(uri); HttpResponse response = client.execute(get); if (response.getStatusLine().getStatusCode() == 200) { HttpEntity entity = response.getEntity(); BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8")); StringBuilder sb = new StringBuilder(); for (String temp = reader.readLine(); temp != null; temp = reader.readLine()) { sb.append(temp); } JSONObject object = JSONObject.parseObject(sb.toString().trim()); int errcode = object.getInteger("errcode"); if (errcode == 0) { //未失效 return true; } } return false; } /** * access_token 介面呼叫憑證 * expires_in access_token介面呼叫憑證超時時間,單位(秒) * refresh_token 使用者重新整理access_token * openid 授權使用者唯一標識 * scope 使用者授權的作用域,使用逗號(,)分隔 * @param APP_ID */ public JSONObject refreshAccessToken(String APP_ID,String refreshToken) throws Exception{ /** * access_token是呼叫授權關係介面的呼叫憑證,由於access_token有效期(目前為2個小時)較短,當access_token超時後,可以使用refresh_token進行重新整理,access_token重新整理結果有兩種: * * 1.若access_token已超時,那麼進行refresh_token會獲取一個新的access_token,新的超時時間; * * 2.若access_token未超時,那麼進行refresh_token不會改變access_token,但超時時間會重新整理,相當於續期access_token。 * * refresh_token擁有較長的有效期(30天)且無法續期,當refresh_token失效的後,需要使用者重新授權後才可以繼續獲取使用者頭像暱稱。 */ String uri = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=" + APP_ID + "&grant_type=refresh_token&refresh_token=" + refreshToken; HttpClient client = HttpClients.createDefault(); HttpGet get = new HttpGet(URI.create(uri)); HttpResponse response = client.execute(get); JSONObject object =new JSONObject(); if (response.getStatusLine().getStatusCode() == 200) { BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8")); StringBuilder builder = new StringBuilder(); for (String temp = reader.readLine(); temp != null; temp = reader.readLine()) { builder.append(temp); } object = JSONObject.parseObject(builder.toString().trim()); } return object; } /** * 得到使用者基本資訊 * @param accessToken * @param openId * @param tClass * @return * @throws Exception */ public <T> T getAppWeiXinUserInfo(String accessToken, String openId, Class<T> tClass) throws Exception{ String uri = "https://api.weixin.qq.com/sns/userinfo?access_token="+accessToken+"&openid="+openId; HttpClient client = HttpClients.createDefault(); HttpGet get = new HttpGet(URI.create(uri)); HttpResponse response = client.execute(get); if (response.getStatusLine().getStatusCode() == 200) { BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8")); StringBuilder builder = new StringBuilder(); for (String temp = reader.readLine(); temp != null; temp = reader.readLine()) { System.out.println(temp); builder.append(temp); } return JSONObject.parseObject(builder.toString(), tClass); } return null; } }
controller:
/**
* @Description: app微信登陸
* @Author: z.hw
*/
@RequestMapping(value = {"getUserInfoByAppCode"})
@ApiOperation(value = "getUserInfoByAppCode", notes = "不分頁", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ApiResponses(value = {
@ApiResponse(code = 404, message = "Not Found"),
@ApiResponse(code = 400, message = "No Name Provided"),
})
publicApiResult getUserInfoByApp(@Validated UserAppAuthority userAppAuthority){
return memberService.getUserInfoByApp(userAppAuthority);
}
請求體:
/**
* @program: maobc-small_routine
* @description: app微信授權
* @author: z.hw
**/
@Data
public class UserAppAuthority {
//新舊app 用來備份 自定義資料
@NotNull(message = "型別不能為空")
@NotEmpty(message = "型別不能為空")
private String type;
//重點需要 app調起微信獲取到的code
@NotEmpty(message = "code不能為空")
@NotNull(message = "code不能為空")
private String code;
}
ApiResult:
@Data
@ToString(callSuper = true)
@EqualsAndHashCode
public class ApiResult<T> implements Serializable {
/**
* 狀態碼
* 0表示成功
*/
private String code = "0000";
/**
* 狀態資訊
*/
private String msg = "呼叫成功";
private Object result;
。。。。。。。。。。。。。
}
業務層:
/**
* @Description: 使用者app微信登陸
* @Param:
* @return:
* @Author: z.hw
*/
public ApiResult getUserInfoByApp(UserAppAuthority userAppAuthority) {
try {
Member member = new Member();
BeanUtils.copyProperties(userAppAuthority, member);
//呼叫微信授權
WeixinLoginUtils weixinLoginUtils = new WeixinLoginUtils();
StringBuilder stringBuilder = weixinLoginUtils.getAccessTokenBycode(commConfig.userAppID, commConfig.userAppSecret, userAppAuthority.getCode());
if (stringBuilder != null) {
if (stringBuilder.toString().trim().contains("errcode")) {
return ApiResult.Fail();
}
JSONObject object = JSONObject.parseObject(stringBuilder.toString().trim());
String accessToken = object.getString("access_token"); //介面呼叫憑證
String openID = object.getString("openid"); //授權使用者唯一標識
//獲取微信使用者基本資訊
WeiXinParam appWeiXinUserInfo = weixinLoginUtils.getAppWeiXinUserInfo(accessToken, openID, WeiXinParam.class);
// TODO 業務邏輯
。。。。。。。。。。。。
return ApiResult.build(member);
}
} catch (Exception e) {
e.printStackTrace();
}
return MaobcApiResult.Fail();
}
Member:
import lombok.*;
import javax.persistence.*;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* @author
*/
@Entity
@Table(name = "cat_member")
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Member implements Serializable {
private static final long serialVersionUID = -27353316177184L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private String id;
/**
* 賬號狀態:0 正常;1 凍結
*/
@Column(name = "status")
private String status;
/**
* del_flag
*/
@Column(name = "del_flag")
private String delFlag;
/**
* 手機
*/
@Column(name = "mobile_phone")
private String mobilePhone;
/**
* 使用者名稱
*/
@Column(name = "user_name")
private String userName;
/**
* 郵箱
*/
@Column(name = "email")
private String email;
/**
* 使用者密碼
*/
@Column(name = "password")
private String password;
/**
* 暱稱
*/
@Column(name = "nickname")
private String nickname;
/**
* 性別
*/
@Column(name = "sex")
private String sex;
/**
* 頭像url
*/
@Column(name = "headimgurl")
private String headimgurl;
/**
* 城市
*/
@Column(name = "city")
private String city;
/**
* 國家
*/
@Column(name = "country")
private String country;
/**
* 省份
*/
@Column(name = "province")
private String province;
/**
* 語言
*/
@Column(name = "language")
private String language;
/**
* 備註
*/
@Column(name = "remark")
private String remark;
/**
* 生日
*/
@Column(name = "birthday")
private String birthday;
/**
* 地址
*/
@Column(name = "address")
private String address;
/**
* 會員積分
*/
@Column(name = "accumulate_points")
private BigDecimal accumulatePoints;
/**
* 平臺會員等級
*/
@Column(name = "level")
private Integer level;
/**
* cat_membership會員型別表的ID
*/
@Column(name = "membership_id")
private String membershipId;
/**
* 建立人
*/
@Column(name = "create_by")
private String createBy;
/**
* 建立時間
*/
@Column(name = "create_date")
private Date createDate;
/**
* 修改人
*/
@Column(name = "update_by")
private String updateBy;
/**
* 修改時間
*/
@Column(name = "update_date")
private Date updateDate;
/**
* 會員是否同意條款標識(0-未同意 1-同意)
*/
@Column(name = "item_status")
private Integer itemStatus;
private String openid;
private String unionId;
private String type;
//是否繫結手機號碼
private String isBindedPhone;
private String oauthId;
private String memberId;
private String outhId;
}
WeiXinParam :
import lombok.Data;
@Data
public class WeiXinParam {
String openid = "";
String unionId = "";
String sex = "1";
String nickname = "";
String city = "";
String province = "";
String country = "";
String avatarUrl = "";
String headimgurl="";
}
參考資料: