谷粒商城-高级-59 -商城业务-认证服务-OAuth2.0 及社交登录
一、OAuth2.0简介
OAuth 2.0是一个应用之间彼此访问数据的开源授权协议。该指南的目标是提供一个OAuth 2.0的很容易理解的概述。
1、使用Code换取AccessToken,Code只能用一次
2、同一个用户的accessToken一段时间是不会变化的,即使多次获取
二、微博授权登录
点击微博登录跳转页:
https://api.weibo.com/oauth2/authorize?client_id=2077705774&response_type=code&redirect_uri=http://auth.gulimall.com/oauth2.0/weibo/success###
该页面扫码,可以获取到code:
扫码成功后,会带参数Code到本地服务获取accessToken:
http://auth.gulimall.com/oauth2.0/weibo/success?code=412c169a1e47f3b3f292d299ffbd4d7e
调用授权接口返回的结果:
{"access_token":"2.00Ry49DC9LqbQCb9cb0e7037dRRo8E","remind_in":"142942","expires_in":142942,"uid":"1883360005","isRealName":"true"}
获取用户详情:
https://api.weibo.com/2/users/show.json?access_token=2.00Ry49DC9LqbQCb9cb0e7037dRRo8E&uid=1883360005
逻辑处理代码:gulimall-auth-server/xxx/auth/controller/OAuth2Controller.java
package com.atguigu.gulimall.auth.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.utils.HttpUtils;
import com.atguigu.common.utils.R;
import com.atguigu.common.vo.MemberResponseVo;
import com.atguigu.gulimall.auth.feign.MemberFeignService;
import com.atguigu.gulimall.auth.vo.SocialUser;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;
import static com.atguigu.common.constant.AuthServerConstant.LOGIN_USER;
/**
* @author: kaiyi
* @create: 2020-09-09 10:21
*/
@Slf4j
@Controller
public class OAuth2Controller {
@Autowired
MemberFeignService memberFeignService;
/**
*
* 这里接收到的参数时k v,所以,不需要@RequestBody接收,如果是Json,则需要@RequestBody注解
*
*/
@GetMapping(value = "/oauth2.0/weibo/success")
public String weibo(@RequestParam("code") String code, HttpSession session) throws Exception {
// 1、封装请求参数
Map<String, String> map = new HashMap<>();
map.put("client_id","2077705774");
map.put("client_secret","40af02bd1c7e435ba6a6e9cd3bf799fd");
map.put("grant_type","authorization_code");
map.put("redirect_uri","http://auth.gulimall.com/oauth2.0/weibo/success");
map.put("code",code);
// 2、根据Code获取AccessToken
HttpResponse response = HttpUtils
.doPost("https://api.weibo.com", "/oauth2/access_token", "post", new HashMap<>(), map, new HashMap<>());
// 3、处理
if(response.getStatusLine().getStatusCode() == 200) {
// 获取到了Token
String json = EntityUtils.toString(response.getEntity());
SocialUser socialUser = JSON.parseObject(json, SocialUser.class);
//知道了哪个社交用户
//1)、当前用户如果是第一次进网站,自动注册进来(为当前社交用户生成一个会员信息,以后这个社交账号就对应指定的会员)
//登录或者注册这个社交用户
System.out.println(socialUser.getAccess_token());
//调用远程服务
R oauthLogin = memberFeignService.oauthLogin(socialUser);
if (oauthLogin.getCode() == 0) {
MemberResponseVo data = oauthLogin.getData("data", new TypeReference<MemberResponseVo>() {});
log.info("登录成功:用户信息:{}",data.toString());
//1、第一次使用session,命令浏览器保存卡号,JSESSIONID这个cookie
//以后浏览器访问哪个网站就会带上这个网站的cookie
//TODO 1、默认发的令牌。当前域(解决子域session共享问题)
//TODO 2、使用JSON的序列化方式来序列化对象到Redis中
session.setAttribute(LOGIN_USER, data);
//2、登录成功跳回首页
return "redirect:http://gulimall.com";
} else {
return "redirect:http://auth.gulimall.com/login.html";
}
}else{
return "redirect:http://auth.gulimall.com/login.html";
}
}
}
三、登录回调及测试
认证微服务远程调用会员微服务进行数据校验和持久化:com/atguigu/gulimall/auth/feign/MemberFeignService.java
package com.atguigu.gulimall.auth.feign;
import com.atguigu.common.utils.R;
import com.atguigu.gulimall.auth.vo.SocialUser;
import com.atguigu.gulimall.auth.vo.UserLoginVo;
import com.atguigu.gulimall.auth.vo.UserRegistVo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
/**
* @author: kaiyi
* @create: 2020-09-08 16:20
*/
@FeignClient("gulimall-member")
public interface MemberFeignService {
@PostMapping(value="/member/member/register")
R register(@RequestBody UserRegistVo vo);
@PostMapping(value = "/member/member/login")
R login(@RequestBody UserLoginVo vo);
@PostMapping(value = "/member/member/oauth2/login")
R oauthLogin(@RequestBody SocialUser socialUser) throws Exception;
}
会员微服务:gulimall-member/xxx/member/controller/MemberController.java
@PostMapping(value = "/oauth2/login")
public R oauthLogin(@RequestBody SocialUser socialUser) throws Exception {
MemberEntity memberEntity = memberService.login(socialUser);
if (memberEntity != null) {
return R.ok().setData(memberEntity);
} else {
return R.error(BizCodeEnum.LOGINACCT_PASSWORD_EXCEPTION.getCode(),BizCodeEnum.LOGINACCT_PASSWORD_EXCEPTION.getMsg());
}
}
业务实现类:gulimall-member/xxx/member/service/impl/MemberServiceImpl.java
@Override
public MemberEntity login(SocialUser socialUser) throws Exception {
//具有登录和注册逻辑
String uid = socialUser.getUid();
//1、判断当前社交用户是否已经登录过系统
MemberEntity memberEntity = this.baseMapper.selectOne(new QueryWrapper<MemberEntity>().eq("social_uid", uid));
if (memberEntity != null) {
//这个用户已经注册过
//更新用户的访问令牌的时间和access_token
MemberEntity update = new MemberEntity();
update.setId(memberEntity.getId());
update.setAccessToken(socialUser.getAccess_token());
update.setExpiresIn(socialUser.getExpires_in());
this.baseMapper.updateById(update);
memberEntity.setAccessToken(socialUser.getAccess_token());
memberEntity.setExpiresIn(socialUser.getExpires_in());
return memberEntity;
} else {
//2、没有查到当前社交用户对应的记录我们就需要注册一个
MemberEntity register = new MemberEntity();
//3、查询当前社交用户的社交账号信息(昵称、性别等)
Map<String,String> query = new HashMap<>();
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");
String gender = jsonObject.getString("gender");
String profileImageUrl = jsonObject.getString("profile_image_url");
register.setNickname(name);
register.setGender("m".equals(gender)?1:0);
register.setHeader(profileImageUrl);
register.setCreateTime(new Date());
register.setSocialUid(socialUser.getUid());
register.setAccessToken(socialUser.getAccess_token());
register.setExpiresIn(socialUser.getExpires_in());
//把用户信息插入到数据库中
this.baseMapper.insert(register);
}
return register;
}
}
为者常成,行者常至
自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)