准备
- gitee oauth2文档
gitee open API文档 - 测试接口工具:postman
- 参数对照表
参数名 | 说明 |
---|---|
client_id | gitee第三方应用添加成功返回来的标识码 |
redirect_uri | 授权成功后跳转的页面,回调地址 |
response_type | gitee授权的uuid,获得一个code 。作用为作为gitee与应用服务间的临时连接标识 |
Client Secret | 密钥,gitee第三方应用添加成功返回来的标识码 |
备注:
① response_type获取的code后,换取的access_tocken在一定时间内都是不变的,但只能使用一次
② 必须对client_secret,以及access_tocken进行保密【交给后台处理】
- 个人应用
这里使用gulimall项目应用
Postman调试接口
-
在gitee中创建第三方应用
应用主页: 用户项目的主要页面,一般不直接跳转到主页,还需要回调地址再次发送后获取access_token
应用主页回调地址: 用户授权后,码云回调到应用,并且回传授权码的地址。【码云会返回一个code
值作为标识码,作为后续动作的标识:如获取用户数据,对开放权限操作等】即gulimall项目中http://gulimall.com/oauth2.0/gitee/success 能处理到code
值的controller
权限: 应用对于gitee的权限操作
-
获取code值
- 在postman中填好参数,然后把完整的请求路径复制到浏览器中发送,保存返回的code值
(postman返回值不好查看到code值,如果要多次请求,记得清楚浏览器中的cookie) - 请求地址为:https://gitee.com/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code
请求,授权登录后会跳转到redirect_url提供的地址,并且在浏览器的url栏会返回code=xxxxxx
值,这就是gitee提供的的uuid
redirect_url地址可以是
创建应用
时候的主页地址也可以是回调地址,主要是后续能处理code值。建议写回调地址
- 获取access_token令牌
- 虽然跳转redirect_url地址是随意填写的,但此时gitee还没给予用户信息,还需要获取access_token令牌去获取用户的数据。保存返回access_token
- 请求地址:https://gitee.com/oauth/token?grant_type=authorization_code&code={code}&client_id={client_id}&redirect_uri={redirect_uri}&client_secret={client_secret}
❗ 注意:这里请求为post
请求
- 获取用户信息
业务代码参考
gitee第三方授权登录流程图:
操作步骤:
- 引入http工具类
(引入引都没影响,为了方便)
- HttpUtils请从
- 创建OAuth2Controller做请求处理
/**
* 社交登录请求
*/
@Slf4j
@Controller
public class OAuth2Controller {
@Autowired
//feign远程调用member服务
private MemberFeignService memberFeignService;
@GetMapping("/oauth2.0/gitee/success")
public String gitee(@RequestParam("code") String code) throws Exception {
Map<String, String> map = new HashMap();
map.put("client_id","71fdfac0ffdf265a0c293206db3f2fac2a6c8627bea1ce1ab137d8a28dbb93eb");
map.put("redirect_uri","http://auth.gulimall.com/oauth2.0/gitee/success");
map.put("client_secret","77dc9a8ceb8c6e3e624d022236910c2aed370f615bb5188da2d04054c2f42960");
map.put("code",code);
map.put("grant_type","authorization_code");
//1.根据code换取access_token
HttpResponse response = HttpUtils.doPost("https://gitee.com", "/oauth/token", "post", new HashMap<>(), map, new HashMap<>());
//2.处理响应回来的json串
if(response.getStatusLine().getStatusCode() == 200){
//获取access_token
String json = EntityUtils.toString(response.getEntity());
SocialUser socialUser = JSON.parseObject(json, SocialUser.class);
//远程调用member服务来处理用户信息注册、校验功能
R r = memberFeignService.oauth2Login(socialUser);
if(r.getCode()==0){
MemberRespVo data = r.getData("data", new TypeReference<MemberRespVo>() {
});
log.info("登录成功:用户信息为:{}"+data.toString());
// 登录成功就跳回首页
return "redirect:http://gulimall.com";
}else {
return "redirect:http://auth.gulimall.com/login.html";
}
}else {
//失败重定向到登录页
return "redirect:http://auth.gulimall.com/login.html";
}
}
}
3.给表usm_member添加字段social_id
,access_token
,expires_in
备注:正常逻辑,应该对每个授权应用做表单。但该练手项目为了避免麻烦,直接在usm_member表中添加social_id,access_token,expires_in三个字段【默认授权应用之间的用户id都不一样。】
4. 远程调用member服务,做注册/登录用户功能 ```java //MemberController.java /** * 登录功能 * 【社交登录】 */ @PostMapping("/oauth2/login") public R oauth2Login(@RequestBody SocialUser socialUser) throws Exception {
MemberEntity entity = memberService.login(socialUser);
if(entity!=null){
return R.ok().setData(entity);
}else {
return R.error(BizCodeEnume.LOGINACCT_PASSWORD_INVAILD_EXCEPTION.getCode(), BizCodeEnume.LOGINACCT_PASSWORD_INVAILD_EXCEPTION.getMsg());
}
}
```java
//MemberServiceImpl.java
@Override
public MemberEntity login(SocialUser socialUser) throws Exception {
//登录和注册合并逻辑
//备注:视频中“微博”社交不需要Access_token也可以获取用户uid,而gitee则需要再发带token请求
//2.1 查询当前社交用户的社交账号信息(uid,昵称,性别等)
Map<String, String> query = new HashMap<>();
query.put("access_token",socialUser.getAccess_token());
HttpResponse response = HttpUtils.doGet("https://gitee.com", "/api/v5/user", "get", new HashMap<String, String>(), query);
if(response.getStatusLine().getStatusCode() == 200){
String json = EntityUtils.toString(response.getEntity());
JSONObject jsonObject = JSON.parseObject(json);
String uid = jsonObject.get("id").toString();
//1.判断当前社交用户是否已经登陆过系统
MemberEntity memberEntity = this.baseMapper.selectOne(new QueryWrapper<MemberEntity>().eq("social_id", uid));
if(memberEntity !=null){
//1.用户有注册记录,更新信息
MemberEntity updateDate = new MemberEntity();
updateDate.setId(memberEntity.getId());
updateDate.setAccessToken(socialUser.getAccess_token());
updateDate.setExpiresIn(socialUser.getExpires_in());
//...其他的不重要,更不更新无所谓
memberDao.updateById(updateDate);
memberEntity.setAccessToken(socialUser.getAccess_token());
memberEntity.setExpiresIn(socialUser.getExpires_in());
return memberEntity;
}else{
//2.没有查到当前社交用户记录,就需要注册一个
MemberEntity register = new MemberEntity();
try{
String name = jsonObject.get("name").toString();
String email = jsonObject.get("email").toString();
String socialId = jsonObject.get("id").toString();
//.....等等信息
register.setNickname(name);
register.setEmail(email);
register.setSocialId(socialId);
}catch (Exception e){
/**
* 远程查询昵称这些不重要的,即是出现问题也可以忽略
*/
}
register.setAccessToken(socialUser.getAccess_token());
register.setExpiresIn(socialUser.getExpires_in());
memberDao.insert(register);
return register;
}
}else {
throw new AccessTokenException(response.getStatusLine().getStatusCode(),response.getStatusLine().getReasonPhrase());
}
}
5.页面渲染,发送请求
<li>
<a href="https://gitee.com/oauth/authorize?client_id={gitee提供的client_id}
&redirect_uri=http://auth.gulimall.com/oauth2.0/gitee/success&response_type=code">
<img style="height: 18px;width: 18px" src="/static/login/JD_img/gitee-log.png" />
<span>gitee</span>
</a>
</li>