之前写过一篇OAuth2 - 第三方登录之微信登录,但是微信的开放平台的资质需要有公司/企业才能注册。如果是个人的话,可以使用其他个人开发者就可以使用的。比如QQ、新浪微博。
QQ的话,需要审核之后才能使用,需要手持身份证照。而微博的话,在开发期间使用无需审核就可以使用。
微博 - 开放平台地址
测试用户即微博用户,输入微博昵称即可。
在开发阶段无需审核,设置完上述内容即可使用。
Web网站的授权
https://api.weibo.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=YOUR_REGISTERED_REDIRECT_URI
该地址中有两个替换的参数
:
client_id:即App Key
redirect_uri:即回调地址
YOUR_REGISTERED_REDIRECT_URI?code=CODE
YOUR_REGISTERED_REDIRECT_URI 即是回调地址。
通过返回的code码去换取Access Token
,只有获取了Token才能为所欲为。
https://api.weibo.com/oauth2/access_token?client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&grant_type=authorization_code&redirect_uri=YOUR_REGISTERED_REDIRECT_URI&code=CODE
这是一个POST请求
,在体验这个流程的时候可以通过postman来进行操作。
该地址中有四个替换的参数:
client_id:即App Key
client_secret:即App Secret
redirect_uri:回调地址
code:登录成功之后,地址栏返回的code值
获取到token之后,就可以凭此调用其他接口(有权限的接口)。
测试 - 获取用户信息:
https://api.weibo.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=YOUR_REGISTERED_REDIRECT_URI
登录授权成功之后,会跳转到回调地址,并且附带一个code。
因为client_secret,也就是AppSecret不能外泄
,所以需要在Java代码内部进行操作。
创建一个Controller作为回调跳转的地址,并且接受code,使用code去交换access_token,其中access_token也是不能外泄的
。
因为在Java代码中需要发送请求,所以需要一个HttpsUtils工具类
:
/**
* HttpUtils请从
* https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java
* 或者直接下载:
* http://code.fegine.com/HttpUtils.zip
*
* 下载相应的依赖请参照
* https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml
* 相关jar包(非pom)直接下载:
* http://code.fegine.com/aliyun-jar.zip
*/
/**
* 微博登录回调方法
* @param code 回调带回来的code值
* @return 跳转的地址
*/
@GetMapping("/oauth2.0/weibo/success")
public String weiboLogin(@RequestParam("code") String code) throw Exception {
// 头信息不能为null
Map<String, String> header = new HashMap<>();
// query不能为null
Map<String, String> query = new HashMap<>();
// 这个Map就是body参数体
Map<String, String> map = new HashMap<>();
// client_id,即App Key
map.put("client_id", WeiboConstant.WEIBO_CLIENT_ID);
// client_secret,即App Secret
map.put("client_secret",WeiboConstant.WEIBO_CLIENT_SECRET);
// 固定的grant_type - authorization_code
map.put("grant_type",WeiboConstant.WEBIBO_GRANT_TYPE);
// 回调地址
map.put("redirect_uri",WeiboConstant.WEIBO_REDIRECT_URI);
// code码
map.put("code",code);
// 发送POST请求 - 获取access_token
HttpResponse response = HttpUtils.doPost("https://api.weibo.com", "/oauth2/access_token", "post", header, query, map);
// 拿到access_token就可以为所欲为了 - 前提是有对应调用接口的权限
if(response.getStatusLine().getStatusCode() == 200){ // 请求状态为200,表示成功
// 通过getEntity方法可以得到如下格式的JSON字符串
/*
{
"access_token": "2.00gvBwvFEBF9VzcseAe2b7c8Jy47iB",
"remind_in": "157679999",
"expires_in": 157679999,
"uid": "5438845756",
"isRealName": "true"
}
*/
// 可以提前创建一个对应这个JSON的POJO类,我这里对应的POJO类为SocialUser
String json = EntityUtils.toString(response.getEntity());
// 转换成对应的POJO类
SocialUser socialUser = JSON.parseObject(json, SocialUser.class);
/**
* 此时可以写一个业务去判断登录的用户是否已经存在
* 一般就通过uid去查询,如果能查询出来对应的用户对象,直接返回即可
* 当然在返回之前还需要更新数据库中对应的access_token、expires_in字段(令牌和令牌过期时间)
*
* 如果数据库中不存在,则需要存入数据库之后返回
*/
// 将这段逻辑封装成loginService中的一个方法
User user = loginService.login(socialUser);
// 成功返回到主页,至于user的信息,可以存储在session中....
return "";
}else{
// 失败返回登录页面,并提示.....
return "";
}
}
// loginService中的login方法
/**
* 登录和注册合并逻辑
* @param socialUser 微博请求返回的对象
* @return User则为系统中真实的对象,即含有昵称、个性签名等的对象
*/
public User login(SocialUser socialUser) throws Exception{
// 获取uid
String uid = socialUser.getUid();
// Dao - 根据uid查询User
User user = userDao.selectUserByUid(uid);
// 要返回的User对象 - userRe
User userRe = new User();
if(user != null){ // user存在
// 替换属性 - 将查询出来的user所有属性复制到userRe中
BeanUtils.copyProperties(user,userRe);
// 设置最新的AccessToken和过期时间
userRe.setAccessToken(socialUser.getAccessToken());
userRe.setExpiresIn(socialUser.getExpiresIn);
// 更新
userDao.updateById(userRe);
}else{ // user不存在,第一次登陆本系统
// 查询微博社交账号的信息
Map<String, String> query = new HashMap<>();
// 根据AccessToken和Uid查询
query.put("access_token",socialUser.getAccess_token());
query.put("uid",socialUser.getUid());
HttpResponse response = HttpUtils.doGet("https://api.weibo.com", "/2/users/show.json", "get", new HashMap<String, String>(), query);
if (response.getStatusLine().getStatusCode() == 200){
// 查询成功
String json = EntityUtils.toString(response.getEntity());
JSONObject jsonObject = JSON.parseObject(json);
// 昵称
String name = jsonObject.getString("name");
userRe.setNickname(name);
// ....更多的信息,如头像地址、个性签名等,一一设置进去
}
userRe.setSocialUid(socialUser.getUid());
userRe.setAccessToken(socialUser.getAccessToken());
userRe.setExpiresIn(socialUser.getExpiresIn());
// 插入到数据库中
userDao.insert(userRe);
}
// 返回userRe
return userRe;
}