先了解下SSO
對於單點登陸淺顯一點的說就是兩種,一種web端的基於Cookie、另一種是跨端的基於Token,一般想要做的都優先做Token吧,個人建議,因爲後期擴展也方便哦。
小程序也是呢,做成token的形式是較好的。
流程圖
PS:圖中4的文字打錯了~
1、啓動服務
2、小程序初次加載app.js校驗token,使用code去換取token
3、檢測User信息是否存在code,不存在則註冊新用戶,最後返回對應用戶Id
4、將隨機Token與UserId一起存入Redis中
5、返回Token信息,小程序存於緩存中,作爲api請求的認證憑證
這個流程思路對什麼後臺語言都是通用的。
具體實現
本文的環境主要是做SpringBoot的,所有對於其他框架可能沒有很好的兼容。
直接上代碼弄起來吧!
首先是開源的話,我們需要確定某些東西是一定要配置的,不能寫死。那麼我寫了兩個Config類來獲取application.yml中的數據,不同用戶可以配置他們的參數。
wechat:
wxurl: https://api.weixin.qq.com/sns/jscode2session?
appid: wxabc2f8828c8e0049
appsecret: cec2412a3af99200f4573c337715329a
granttype: authorization_code
redis:
expire: 7200
wxtoken: wx_token_%s
spring:
redis:
port: 6379
host: 192.168.192.132
我這邊了以上的參數作爲組件中的可配置,其實部分可以作爲默認的,不過暫時沒有改了,如果你像要使用就是暫時都是必選的。
項目目錄
config包中的就是對配置參數的讀取。
utils包是存放一個Http的請求工具。
最核心的就是我們的WechatTemplate類了。
根據業務,我們需要以下幾個方法:
根據小程序傳遞來的code獲取openid
/**
* 獲取OpenId
* @param code 微信code
* @return {@link Map}
*/
public Map<String,String> getOpenId(String code){
Map<String,String> back = new HashMap<>();
Map<String,String> wxResult = new HashMap<>();
String wxLoginUrl = weChatComponent.url(code);
String result = HttpServiceUtils.sendGet(wxLoginUrl);
if (result.isEmpty()){
back.put("null","null");
}else{
wxResult = (Map) JSON.parse(result);
if (wxResult.containsKey("errCode")){
//存在錯誤碼
back.put("errCode",wxResult.get("errCode"));
}else{
//不存在錯誤碼
String session_key = wxResult.get("session_key");
back.put("session_key",session_key);
log.info("【微信Token】session_key:"+session_key);
String openid = wxResult.get("openid");
back.put("openid",openid);
}
}
return back;
}
根據openid,我們可以和數據庫對接得到用戶id並生成自己Token
/**
* 生成Token
* @param userid 用戶id
* @return {@link String}
*/
public String granToken(String userid){
return saveToRedis(userid);
}
/**
* 獲取Token並存放到redis中
* @param userid 用戶id
* @return {@link String}
*/
private String saveToRedis(String userid) {
String token = UUID.randomUUID().toString();
Integer expire = redisComponent.getExpire();
redisTemplate.opsForValue().set(String.format(redisComponent.getWxtoken(),token),userid,expire, TimeUnit.SECONDS);
return token;
}
還有校驗Token,是否存在
/**
* 校驗是否存在用戶信息
* @param token 唯一值
* @return {@link Boolean}
*/
public boolean verifyToken(String token){
String tokenValue = redisTemplate.opsForValue().get(String.format(redisComponent.getWxtoken(),token));
if (tokenValue.isEmpty()){
return false;
}
return true;
}
Maven包
接着打包發到Maven中央倉庫中,生成自己的maven包
<dependency>
<groupId>com.github.UncleCatMySelf</groupId>
<artifactId>wechat-login</artifactId>
<version>2.1.0</version>
</dependency>
如何使用?
我在Github項目中,做了Demo演示。
我們僅需在Service中調用,並使用對應方法即可。
@Slf4j
@Service
public class UserServiceImpl implements UserService {
@Autowired
private WechatTemplate wechatTemplate;
@Autowired(required = true)
private ResultVOUtil resultVOUtil;
@Override
public ResultVo getToken(String code) {
Map<String,String> result = wechatTemplate.getOpenId(code);
if (result.containsKey("null")){
return resultVOUtil.error(555,"返回值爲空");
}else if(result.containsKey("errCode")){
return resultVOUtil.error(666,"存在錯誤碼,內容:"+result.get("errCode"));
}else{
String sessionKey = result.get("session_key");
String openid = result.get("openid");
log.info("openid="+openid+"--sessionKey="+sessionKey);
//與存在用戶的openid信息進行對比,返回用戶id,不存在則註冊用戶
String userid = "WX_10agg";//模擬獲取到的用戶id
String token = wechatTemplate.granToken(userid);
return resultVOUtil.success(token);
}
}
@Override
public ResultVo verifyToken(String token) {
return resultVOUtil.success(wechatTemplate.verifyToken(token));
}
}
tip:記得添加掃描包路徑,@ComponentScan({"com.github.unclecatmyself"})
GitHub
wechat-login
一個配合小程序登錄的前後臺組件(Token形式),附帶前端小程序代碼