认证服务分为两种,一种是社交登录,一种是单点登录,都交给认证中心(OAuth2.0)来处理,用一个专门的服务来作这个认证中心,所有的登录注册都是由这个认证中心来处理的,由于注册要发短信,短信又是调用了阿里云的接口, 这个发验证码短信的组件放到了第三方服务中,所以又需要调用第三方服务来发短信,最终的登录注册实现是写在用户服务里的,所以还需要远程调用用户服务
(1)前端实现发送短信后倒计时效果和发送请求/sms/sendCode给后端处理
/*** 发送验证码请求给后端*/$(function () {$("#sendCode").click(function () {//2、倒计时//只有class里有disabled就表示还在倒计时中,什么都不干(用于防止在倒计时期间重复发送验证码)if($(this).hasClass("disabled")) {//正在倒计时中} else {//1、给指定手机号发送验证码$.get("/sms/sendCode?phOne=" + $("#phoneNum").val(),function (data) {if(data.code != 0) {alert(data.msg);}});timeoutChangeStyle();}});});/*** 实现验证码倒计时效果* @type {number}*/var num = 60; //倒计时60sfunction timeoutChangeStyle() {//点击发送验证码后就设置其class为disabled(用于防止在倒计时期间重复发送验证码)$("#sendCode").attr("class","disabled");//倒计时结束if(num == 0) {$("#sendCode").text("发送验证码");num = 60;//清空前面加的class$("#sendCode").attr("class","");} else {var str = num + "s 后再次发送";$("#sendCode").text(str);//1s后再调用自身方法来实现倒计时setTimeout("timeoutChangeStyle()",1000);}num --;}
(2)在认证服务的LoginController来处理请求/sms/sendCode(发短信验证码)
分流程:(其实就是把短信验证码以下面的格式存到缓存再真正发送短信验证码)
Redis缓存中验证码的格式sms:code:123456789->123456_1646981054661 ,123456789是手机号,123456表示验证码,1646981054661表示存入缓存的时间
1>判断Redis缓存里有没有这个手机号对应的验证码信息
2>如果Redis缓存中有这个验证码信息那就要判断时间合法性(其实就是验证码有没有过期)
3>创建验证码并且拼装成存入Redis缓存中的value值格式
4>调用第三方服务来真正发送验证码
/**
* 短信验证码
* @param phone
* @return
*/
@ResponseBody
@GetMapping(value = "/sms/sendCode")
public R sendCode(@RequestParam("phone") String phone) {/*** 接口防刷*///把验证码从缓存中提取出来//(缓存中验证码的格式sms:code:123456789->123456_1646981054661 ,123456789是手机号,123456表示验证码,1646981054661表示存入缓存的时间)String redisCode = stringRedisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone);if (!StringUtils.isEmpty(redisCode)) {//把存入缓存的验证码的值给提取出来(格式是123456_1646981054661 ,123456表示验证码,1646981054661表示存入缓存的时间)long currentTime = Long.parseLong(redisCode.split("_")[1]);//活动存入redis的时间,用当前时间减去存入redis的时间,判断用户手机号是否在60s内发送验证码if (System.currentTimeMillis() - currentTime <60000) {//60s内不能再发// BizCodeEnum.SMS_CODE_EXCEPTION=10002 BizCodeEnum.SMS_CODE_EXCEPTION = 10002return R.error(BizCodeEnum.SMS_CODE_EXCEPTION.getCode(),BizCodeEnum.SMS_CODE_EXCEPTION.getMessage());}}/*** 2、创建验证码存入redis.存key-phone,value-code*/int code = (int) ((Math.random() * 9 + 1) * 100000);String codeNum = String.valueOf(code);//存入缓存的验证码格式是123456_1646981054661 加系统时间是为了防止多次刷新验证码String redisStorage = codeNum + "_" + System.currentTimeMillis();//存入redis,防止同一个手机号在60秒内再次发送验证码(存入缓存的格式sms:code:123456789->123456 ,其中123456789是手机号,123456是验证码)stringRedisTemplate.opsForValue().set(AuthServerConstant.SMS_CODE_CACHE_PREFIX+phone,redisStorage,10, TimeUnit.MINUTES);//AuthServerConstant.SMS_CODE_CACHE_PREFIX = sms:code:// String codeNum = UUID.randomUUID().toString().substring(0,6);thirdPartFeignService.sendCode(phone, codeNum);return R.ok();}
注意:这里的短信验证码不是第三方服务发送的,具体短信验证码的内容是上面的sendCode方法随机生成的,这个验证码甚至可以自定义为666666,所以这个验证码的内容在上面sendCode方法就已经存到Redis缓存中,方便后面进行验证码校验
(3)远程调用第三方服务来真正发送验证码
package com.saodai.saodaimall.auth.feign;import com.saodai.common.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;/*** 远程调用第三方服务来发送验证码**/@FeignClient("saodaimall-third-party")
public interface ThirdPartFeignService {@GetMapping(value = "/sms/sendCode")R sendCode(@RequestParam("phone") String phone, @RequestParam("code") String code);}
package com.saodai.saodaimall.thirdparty.controller;import com.saodai.common.utils.R;
import com.saodai.saodaimall.thirdparty.component.SmsComponent;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;/*** 短信验证码的控制器**/@RestController
@RequestMapping(value = "/sms")
public class SmsSendController {@Resourceprivate SmsComponent smsComponent;/*** 提供给别的服务进行调用* @param phone* @param code* @return*/@GetMapping(value = "/sendCode")public R sendCode(@RequestParam("phone") String phone, @RequestParam("code") String code) {//发送验证码smsComponent.sendCode(phone,code);return R.ok();}}
package com.saodai.saodaimall.thirdparty.component;import com.saodai.saodaimall.thirdparty.util.HttpUtils;
import lombok.Data;
import org.apache.http.HttpResponse;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import java.util.HashMap;
import java.util.Map;/*** 短信验证码发送的组件类(提供发送短信验证码的接口)**/@ConfigurationProperties(prefix = "spring.cloud.alicloud.sms")
@Data
@Component
public class SmsComponent {private String host;private String path;private String appcode;public void sendCode(String phone,String code) {String method = "POST";Map
package com.saodai.saodaimall.thirdparty.util;import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;/**
* 阿里云短信验证码接口要用的工具类
*/
public class HttpUtils {/*** get* * @param host* @param path* @param method* @param headers* @param querys* @return* @throws Exception*/public static HttpResponse doGet(String host, String path, String method, Map
spring:cloud:alicloud:#短信验证码的配置sms:host: https://dfsns.market.alicloudapi.compath: /data/send_smsappcode: dbc663defb63426caefc7be0a8fe8cdf
整个配置文件里就只有appcode是自己购买短信服务后唯一的码,其他的都是固定配置
AppCode获取地址:阿里云登录 - 欢迎登录阿里云,安全稳定的云计算服务平台
(1)前端以表单的形式发送请求/register给后端
(2)在认证服务的LoginController来处理请求/register
分流程:
1>获取用户输入的验证码和缓存里的验证码(这里要判断缓存中验证码为不为空)进行比较,看是否相同
2>验证码相同就立马删除验证码(令牌机制),验证码不同报错同时重定向到注册界面
3>远程调用会员服务进行真正的用户注册
4>远程调用成功就重定向到首页,失败就把错误消息封装成map同时重定向到注册界面
/**
* 用户注册
* TODO: 重定向携带数据:利用session原理,将数据放在session中。
* TODO:只要跳转到下一个页面取出这个数据以后,session里面的数据就会删掉
* TODO:分布下session问题
* RedirectAttributes:重定向也可以保留数据,不会丢失
*
* @return
*/
@PostMapping(value = "/register")
public String register(@Valid UserRegisterVo vos, BindingResult result,RedirectAttributes attributes) {//1、效验验证码String code = vos.getCode();//获取存入Redis里的验证码(redisCode的格式是123456_1646981054661 ,123456表示验证码,1646981054661表示存入缓存的时间)String redisCode = stringRedisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + vos.getPhone());//判断redis的对应的验证码是否为空if (!StringUtils.isEmpty(redisCode)) {//判断验证码是否相同if (code.equals(redisCode.split("_")[0])) {//删除验证码;令牌机制stringRedisTemplate.delete(AuthServerConstant.SMS_CODE_CACHE_PREFIX+vos.getPhone());//验证码通过,真正注册,调用远程服务进行注册R register = memberFeignService.register(vos);//register.getCode() == 0表示远程调用成功if (register.getCode() == 0) {//成功return "redirect:http://saodaimall.com";} else {//失败Map
}
package com.saodai.saodaimall.auth.vo;import lombok.Data;
import org.hibernate.validator.constraints.Length;import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;/*** 用户注册信息封装类**/@Data
public class UserRegisterVo {@NotEmpty(message = "用户名不能为空")@Length(min = 6, max = 19, message="用户名长度在6-18字符")private String userName;@NotEmpty(message = "密码必须填写")@Length(min = 6,max = 18,message = "密码必须是6—18位字符")private String password;@NotEmpty(message = "手机号不能为空")@Pattern(regexp = "^[1]([3-9])[0-9]{9}$", message = "手机号格式不正确")private String phone;@NotEmpty(message = "验证码不能为空")private String code;}
(3)远程调用会员服务来实现真正的注册
/*** 会员注册功能* @param vo* @return*/@PostMapping(value = "/register")public R register(@RequestBody MemberUserRegisterVo vo) {try {memberService.register(vo);} catch (PhoneException e) {//BizCodeEnum.PHONE_EXIST_EXCEPTION=存在相同的手机号 15002return R.error(BizCodeEnum.PHONE_EXIST_EXCEPTION.getCode(),BizCodeEnum.PHONE_EXIST_EXCEPTION.getMessage());} catch (UsernameException e) {//BizCodeEnum.USER_EXIST_EXCEPTION=商品库存不足 21000return R.error(BizCodeEnum.USER_EXIST_EXCEPTION.getCode(),BizCodeEnum.USER_EXIST_EXCEPTION.getMessage());}return R.ok();}/*** 会员注册*/@Overridepublic void register(MemberUserRegisterVo vo) {MemberEntity memberEntity = new MemberEntity();//设置默认等级MemberLevelEntity levelEntity = memberLevelDao.getDefaultLevel();memberEntity.setLevelId(levelEntity.getId());//设置其它的默认信息//检查用户名和手机号是否唯一。感知异常,异常机制(异常机制就是问题就抛出具体异常,没问题就继续执行下面的语句)checkPhoneUnique(vo.getPhone());checkUserNameUnique(vo.getUserName());memberEntity.setNickname(vo.getUserName());memberEntity.setUsername(vo.getUserName());//密码进行MD5盐值加密(盐值加密同一个数据的每次加密结果是不一样的,通过match方法来密码校验)// (注意这里不能用md5直接加密放数据库,因为彩虹表可以破解md5,所谓彩虹表就是通过大量的md5数据反向退出md5// 注意MD5是不可逆,但是可暴力通过彩虹表破解)BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();String encode = bCryptPasswordEncoder.encode(vo.getPassword());memberEntity.setPassword(encode);memberEntity.setMobile(vo.getPhone());memberEntity.setGender(0);memberEntity.setCreateTime(new Date());//保存数据this.baseMapper.insert(memberEntity);}/*** 检查手机号是否重复的异常机制方法* @param phone* @throws PhoneException*/@Overridepublic void checkPhoneUnique(String phone) throws PhoneException {Long phOneCount= this.baseMapper.selectCount(new QueryWrapper
分流程:(封装MemberEntity对象)
1>设置默认等级
package com.saodai.saodaimall.member.entity;import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;import java.io.Serializable;
import java.math.BigDecimal;/*** 会员等级*/
@Data
@TableName("ums_member_level")
public class MemberLevelEntity implements Serializable {private static final long serialVersiOnUID= 1L;/*** id*/@TableIdprivate Long id;/*** 等级名称*/private String name;/*** 等级需要的成长值*/private Integer growthPoint;/*** 是否为默认等级[0->不是;1->是]*/private Integer defaultStatus;/*** 免运费标准*/private BigDecimal freeFreightPoint;/*** 每次评价获取的成长值*/private Integer commentGrowthPoint;/*** 是否有免邮特权*/private Integer priviledgeFreeFreight;/*** 是否有会员价格特权*/private Integer priviledgeMemberPrice;/*** 是否有生日特权*/private Integer priviledgeBirthday;/*** 备注*/private String note;}
2>检查用户名和手机号是否唯一,通过异常机制来感知异常(异常机制就是问题就抛出具体异常,没问题就继续执行下面的语句)package com.saodai.saodaimall.member.exception;public class UsernameException extends RuntimeException {public UsernameException() {super("存在相同的用户名");}
}
package com.saodai.saodaimall.member.exception;public class PhoneException extends RuntimeException {public PhoneException() {super("存在相同的手机号");}
}
3>密码进行MD5盐值加密
4>保存用户信息到数据库中
package com.saodai.saodaimall.member.vo;import lombok.Data;/*** 会员注册类**/@Data
public class MemberUserRegisterVo {private String userName;private String password;private String phone;}
package com.saodai.saodaimall.member.entity;import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;import java.io.Serializable;
import java.util.Date;/*** 会员*/
@Data
@TableName("ums_member")
public class MemberEntity implements Serializable {private static final long serialVersiOnUID= 1L;/*** id*/@TableIdprivate Long id;/*** 会员等级id*/private Long levelId;/*** 用户名*/private String username;/*** 密码*/private String password;/*** 昵称*/private String nickname;/*** 手机号码*/private String mobile;/*** 邮箱*/private String email;/*** 头像*/private String header;/*** 性别*/private Integer gender;/*** 生日*/private Date birth;/*** 所在城市*/private String city;/*** 职业*/private String job;/*** 个性签名*/private String sign;/*** 用户来源*/private Integer sourceType;/*** 积分*/private Integer integration;/*** 成长值*/private Integer growth;/*** 启用状态*/private Integer status;/*** 注册时间*/private Date createTime;/*** 社交登录用户的ID*/private String socialId;/*** 社交登录用户的名称*/private String socialName;/*** 社交登录用户的自我介绍*/private String socialBio;}
(1)前端以表单的形式发送请求/login给后端
(2)在认证服务的LoginController来处理请求/login
/**
* 普通手机账号登录
* @param vo
* @param attributes
* @param session
* @return
*/
@PostMapping(value = "/login")
public String login(UserLoginVo vo, RedirectAttributes attributes, HttpSession session) {//远程登录R login = memberFeignService.login(vo);//login.getCode() == 0表示远程调用成功if (login.getCode() == 0) {MemberResponseVo data = login.getData("data", new TypeReference
package com.saodai.saodaimall.auth.vo;import lombok.Data;/*** 用户登录信息封装类**/@Data
public class UserLoginVo {//账户private String loginacct;//密码private String password;
}
package com.saodai.common.vo;import lombok.Data;
import lombok.ToString;import java.io.Serializable;
import java.util.Date;/***会员信息**/@ToString
@Data
public class MemberResponseVo implements Serializable {private static final long serialVersiOnUID= 5573669251256409786L;private Long id;/*** 会员等级id*/private Long levelId;/*** 用户名*/private String username;/*** 密码*/private String password;/*** 昵称*/private String nickname;/*** 手机号码*/private String mobile;/*** 邮箱*/private String email;/*** 头像*/private String header;/*** 性别*/private Integer gender;/*** 生日*/private Date birth;/*** 所在城市*/private String city;/*** 职业*/private String job;/*** 个性签名*/private String sign;/*** 用户来源*/private Integer sourceType;/*** 积分*/private Integer integration;/*** 成长值*/private Integer growth;/*** 启用状态*/private Integer status;/*** 注册时间*/private Date createTime;/*** 社交登录用户的ID*/private String socialId;/*** 社交登录用户的名称*/private String socialName;/*** 社交登录用户的自我介绍*/private String socialBio;}
(3)远程调用会员服务来实现真正的登录
/*** 会员登录功能* @param vo* @return*/@PostMapping(value = "/login")public R login(@RequestBody MemberUserLoginVo vo) {//MemberUserLoginVo就是上面的UserLoginVo只是类名不一样MemberEntity memberEntity = memberService.login(vo);if (memberEntity != null) {return R.ok().setData(memberEntity);} else {return R.error(BizCodeEnum.LOGINACCT_PASSWORD_EXCEPTION.getCode(),BizCodeEnum.LOGINACCT_PASSWORD_EXCEPTION.getMessage());}}/*** 会员登录功能* @param vo* @return*/@Overridepublic MemberEntity login(MemberUserLoginVo vo) {//获取用户登录账号String loginacct = vo.getLoginacct();String password = vo.getPassword();//1、去数据库查询 SELECT * FROM ums_member WHERE username = ? OR mobile = ?//通过用户名或手机号登录都是可以的MemberEntity memberEntity = this.baseMapper.selectOne(new QueryWrapper
package com.saodai.saodaimall.member.vo;import lombok.Data;/*** 会员登录**/@Data
public class MemberUserLoginVo {private String loginacct;private String password;}
这里由于微博开发者权限申请太慢了就使用gitee来实现社交登录
这个跟以往的模式不一样,以往是前段直接给后端发送请求,然后后端处理请求,这个是先调用第三方应用作为社交登录(也就是先跳转到gitee的登录授权页面),然后用户登录自己的gitee账号密码进行授权,授权成功后会跳转到指定的应用回调地址,然后在后端来处理这个应用回调地址的请求
gitee开发者后台管理链接:https://gitee.com/oauth/applications/16285
调用gitee第三方登录的url地址:Client ID&redirect_uri=自己应用的成功回调地址&response_type=code&state=1">
分流程:(其实就只有三行代码是要自己配置的(OAuth2Controller的gitee的42-44行),其他的基本上是固定的)
1>封装AccessTokenDTO对象然后发给码云服务器,如果AccessTokenDTO对象正确的话就返回一个通行令牌(其实准确来说是用户授权后会返回一个code,然后通过code来去找码云服务器获取到一个通行令牌,最后通过这个通行令牌去找码云服务器要这个用户在gitee上公开的资料信息)
2>获取到了access_token通行令牌,转为通用gitee社交登录GiteeUser对象
3>远程调用会员服务来进行社交登录
package com.saodai.saodaimall.auth.controller;import com.alibaba.fastjson.TypeReference;
import com.saodai.common.utils.R;
import com.saodai.common.vo.MemberResponseVo;
import com.saodai.saodaimall.auth.component.GitheeProvider;
import com.saodai.saodaimall.auth.feign.MemberFeignService;
import com.saodai.saodaimall.auth.vo.AccessTokenDTO;
import com.saodai.saodaimall.auth.vo.GiteeUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;import javax.servlet.http.HttpSession;import static com.saodai.common.constant.AuthServerConstant.LOGIN_USER;/**
* 社交第三方授权登录
**/@Slf4j
@Controller
public class OAuth2Controller {@Autowiredprivate MemberFeignService memberFeignService;@Autowiredprivate AccessTokenDTO accessTokenDTO;@Autowiredprivate GitheeProvider githeeProvider;@GetMapping(value = "/callback")// /callback?code=e867a1f4575d4a6161e3249423a0403898253bc593e4b031a8771739ee6769f5&state=1public String gitee(@RequestParam(name = "code") String code,@RequestParam(name = "state") String state, HttpSession session) throws Exception {System.out.println(code);//下面三行代码都是自己应用的值,可以在gitee的第三方应用中看到对应的值accessTokenDTO.setClient_id("32459f971ce6d89cfb9f70899525455d0653cb804f16b38a304e3447dc97d673");accessTokenDTO.setClient_secret("f3046c911c03cadcded986062708150d4232af3ca6aef0259e5a0198d2c15ba5");accessTokenDTO.setRedirect_uri("http://auth.saodaimall.com/callback");accessTokenDTO.setCode(code);accessTokenDTO.setState(state);String accessToken = githeeProvider.getAccessToken(accessTokenDTO);//2、处理if (!StringUtils.isEmpty(accessToken)) {//获取到了access_token,转为通用gitee社交登录对象GiteeUser giteeUser = githeeProvider.getGiteeUser(accessToken);//知道了哪个社交用户//1)、当前用户如果是第一次进网站,自动注册进来(为当前社交用户生成一个会员信息,以后这个社交账号就对应指定的会员)//登录或者注册这个社交用户//调用远程服务R oauthLogin = memberFeignService.oauthLogin(giteeUser);if (oauthLogin.getCode() == 0) {MemberResponseVo memberRespOnseVo= oauthLogin.getData("data", new TypeReference
package com.saodai.saodaimall.auth.vo;/*** AccessTokenDTO对象封装(gitee社交登录令牌)*/import org.springframework.stereotype.Component;@Component
public class AccessTokenDTO {private String client_id;private String client_secret;private String code;private String redirect_uri;private String state;public String getClient_id() {return client_id;}public void setClient_id(String client_id) {this.client_id = client_id;}public String getClient_secret() {return client_secret;}public void setClient_secret(String client_secret) {this.client_secret = client_secret;}public String getCode() {return code;}public void setCode(String code) {this.code = code;}public String getRedirect_uri() {return redirect_uri;}public void setRedirect_uri(String redirect_uri) {this.redirect_uri = redirect_uri;}public String getState() {return state;}public void setState(String state) {this.state = state;}
}
package com.saodai.saodaimall.auth.component;import com.alibaba.fastjson.JSON;
import com.saodai.saodaimall.auth.vo.AccessTokenDTO;
import com.saodai.saodaimall.auth.vo.GiteeUser;
import okhttp3.*;
import org.springframework.stereotype.Component;import java.io.IOException;/*** 请求码云服务器*/
@Component
public class GitheeProvider {//发起post请求获取AccessTokenpublic String getAccessToken(AccessTokenDTO accessTokenDTO){MediaType mediaType= MediaType.get("application/json; charset=utf-8");OkHttpClient client = new OkHttpClient();RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(accessTokenDTO));Request request = new Request.Builder().url("https://gitee.com/oauth/token?grant_type=authorization_code&code="+accessTokenDTO.getCode()+"&client_id="+accessTokenDTO.getClient_id()+"&redirect_uri="+accessTokenDTO.getRedirect_uri()+"&client_secret="+accessTokenDTO.getClient_secret()).post(body).build();try (Response respOnse= client.newCall(request).execute()) {String string = response.body().string();System.out.println(string);String str1 = string.split(":")[1];String str2 = str1.split("\"")[1];return str2;} catch (IOException e) {e.printStackTrace();}return null;}//发起get请求返回GitUser对象,public GiteeUser getGiteeUser(String token){OkHttpClient client = new OkHttpClient();Request request = new Request.Builder().url("https://gitee.com/api/v5/user?access_token="+token).build();try (Response respOnse= client.newCall(request).execute()) {String string=response.body().string();GiteeUser giteeUser = JSON.parseObject(string, GiteeUser.class);return giteeUser;} catch (IOException e) {e.printStackTrace();}return null;}
}
package com.saodai.saodaimall.auth.vo;import lombok.Data;/*** GiteeUser对象封装(社交登录的gitee对象)*/
@Data
public class GiteeUser {//gitee用户名称private String name;//gitee用户idprivate String id;//gitee用户自我介绍private String bio;}
/*** 社交登录* @param giteeUser* @return* @throws Exception*/@PostMapping(value = "/oauth2/login")public R oauthLogin(@RequestBody GiteeUser giteeUser) throws Exception {MemberEntity memberEntity = memberService.login(giteeUser);if (memberEntity != null) {return R.ok().setData(memberEntity);} else {return R.error(BizCodeEnum.LOGINACCT_PASSWORD_EXCEPTION.getCode(),BizCodeEnum.LOGINACCT_PASSWORD_EXCEPTION.getMessage());}}/*** 社交登录* @param giteeUser* @return* @throws Exception*/@Overridepublic MemberEntity login(GiteeUser giteeUser) throws Exception {//获取gitee用户唯一idString giteeUserId = giteeUser.getId();//1、判断当前社交用户是否已经登录过系统MemberEntity memberEntity = this.baseMapper.selectOne(new QueryWrapper
package com.saodai.saodaimall.member.entity;import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;import java.io.Serializable;
import java.util.Date;/*** 会员*/
@Data
@TableName("ums_member")
public class MemberEntity implements Serializable {private static final long serialVersiOnUID= 1L;/*** id*/@TableIdprivate Long id;/*** 会员等级id*/private Long levelId;/*** 用户名*/private String username;/*** 密码*/private String password;/*** 昵称*/private String nickname;/*** 手机号码*/private String mobile;/*** 邮箱*/private String email;/*** 头像*/private String header;/*** 性别*/private Integer gender;/*** 生日*/private Date birth;/*** 所在城市*/private String city;/*** 职业*/private String job;/*** 个性签名*/private String sign;/*** 用户来源*/private Integer sourceType;/*** 积分*/private Integer integration;/*** 成长值*/private Integer growth;/*** 启用状态*/private Integer status;/*** 注册时间*/private Date createTime;/*** 社交登录用户的ID*/private String socialId;/*** 社交登录用户的名称*/private String socialName;/*** 社交登录用户的自我介绍*/private String socialBio;}