一.登錄流程
1.微信小程序端發起請求並攜帶主要參數;
2.java後臺接收到登錄請求後,根據臨時憑證code去調用微信接口獲取用戶唯一標識openId和sessionKey;
3.使用openId去查詢數據庫(openId是會員的的唯一標識)
a.若openId存在,直接登錄成功;
b.若openId’不存在,我們把openId寫入到數據庫,並且讓他登錄
4.根據openId查詢redis數據庫,判斷openId對應的skey是否存在,如果存在刪除原來的老skey以及對應的openId和sessionKey(爲了安全,保證每次登錄的key都是最新的)
5.通過uuid生成唯一的skey,用openId做鍵,skey做值,存入到redis中
6.然後把skey做鍵,openId和sessionKey的json串做值也重新存入到redis中
7.根據解密算法,參數有encryptedData、sessionKey和iv,獲取用戶信息userInfo,如果userInfo字段不滿足需要,可通過userInfo.put( “balance”,user.getUbalance() );添加所需要的字段和值
8.將微信小程序需要的數據封裝到map容器中,返回給小程序端
二.獲取測試號的AppID和AppSecret
三.在後臺只需要發起一個get請求
https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
微信小程序端發起登錄請求,攜帶的參數主要有:
code:loginRes.code,//臨時登錄憑證
rawData:infoRes.rawData,//用戶非敏感信息
signature:infoRes.signature,//簽名
encrypteData:infoRes.encryptedData,//用戶敏感信息
iv:infoRes.iv//解密算法的向量
需要的數據主要有:
result、userInfo和skey,result用來判斷是否登錄成功,userInfo是用戶的一些信息,保存在緩存中,不用每次都從後臺獲取,skey是用戶登錄態標識,也放在緩存中,如果skey存在就直接登錄,維護用戶的登錄狀態,具有時效性
4.通過postMan發請求測試獲取到了sessionKey和openId
@Configuration
public class UserRealm extends AuthorizingRealm{
private final static String WX_LOGIN_URL="https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";
@Value("${wx.appid}")
private String wxAppId;
@Value("${wx.secret}")
private String wxSecret;
//spring提供我們發http請求的
@Autowired
private RestTemplate restTemplate;
@Autowired
private UserService userService;
/**
* 授權
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
/**
* 登錄
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String wxCode = token.getPrincipal().toString();
//使用code給微信WX_LOGIN_URL換取openId
String openId = getOpenIdByCode(wxCode);
User user=userService.findByUsername(openId);
if(user==null) {
//該用戶不存在
//自動創建用戶,在微信小程序裏面,不需要通過用戶名密碼登錄
user =new User();
user.setUserId(openId);
//新增一個會員
userService.save(user);
}
return new SimpleAuthenticationInfo(openId, "WX_LOGIN",wxCode);
}
private String getOpenIdByCode(String wxCode) {
String url = String.format(WX_LOGIN_URL, wxAppId,wxSecret,wxCode);
String wxResult = restTemplate.getForObject(url, String.class);
JSONObject json = JSONUtil.parseObj(wxResult);
//代表訪問微信服務器時,發生錯誤
if(json.containsKey("errcode")) {
Long errCode = json.get("errcode",Long.class);
if(errCode==40029) {
//代表是code錯誤
throw new RuntimeException("從微信來的code錯誤");
}
}
//獲取openId
String openId = json.get("openid",String.class);
return openId;
}
@RestController
public class LoginController {
@PostMapping("/login")
public ResponseEntity<Object> login(@RequestBody LoginParam loginParam){
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(loginParam.getPrincipal(), "WX_LOGIN");
Subject subject = SecurityUtils.getSubject();
String token=null;
Map<String, Object> result =new HashMap<String, Object>(3);
try {
subject.login(usernamePasswordToken);
token = subject.getSession().getId().toString();
User user = (User) subject.getPrincipal();
result.put("nickName", user.getNickName());
result.put("userStutas", user.getStatus());
result.put("access_token", token);
return ResponseEntity.ok(result);
} catch (AuthenticationException e) {
e.printStackTrace();
}
return ResponseEntity.ok(result);
}
}
五.通過微信小程序端調試,登錄請求的response返回了access_token和nickName