You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1051 lines
37 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 商城认证服务
# 一、搭建认证服务环境
  结合我们前面介绍的商城的架构我们需要单独的搭建一个认证服务。
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/6e06e02a4c8d4f4d8af8d9b38ab2e4f3.png)
## 1.创建项目
  首先创建一个SpringBoot项目然后添加对应的依赖
```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.12</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.msb.mall</groupId>
<artifactId>mall-auth-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mall-auth_server</name>
<description>认证服务</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2020.0.1</spring-cloud.version>
</properties>
<dependencies>
<!-- 公共依赖 -->
<dependency>
<groupId>com.msb.mall</groupId>
<artifactId>mall-commons</artifactId>
<version>0.0.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
```
## 2.注册中心配置
&emsp;&emsp;我们需要把认证服务注册到Nacos中添加对应的依赖然后完成对应的配置
```properties
# Nacos服务注册
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.56.100:8848
application:
name: mall-auth_server
# 统一的全局的--设置服务器响应给客户端的日期时间格式
jackson:
date-format: yyyy-MM-dd HH:mm:ss
thymeleaf:
cache: false # 关闭Thymeleaf的缓存
server:
port: 30000
```
放开Nacos注册中心
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/caf33f23f60a49b2929ae46f20386068.png)
然后启动测试
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/42b66d7705cd45d88ceff0299efd1bdb.png)
## 3.登录和注册页面
&emsp;&emsp;然后我们整理登录和注册的相关资源,首先把登录和注册的模板文件拷贝进项目
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/2eab568483cc4551bf8a1fcc32432cee.png)
然后把对应的静态文件拷贝到Nginx中。
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/0a9f8e13aca5493893aaf8f844845422.png)
然后我们需要在host文件中添加对应的配置
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/704667a877ec4c7daec5355f885fb721.png)
修改Nginx的反向代理的配置
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/63fac10a01724a40bbaa68ca8f187d06.png)
然后重启Nginx的服务![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/82c83ec09182425c9ed8e8b853a38ddc.png)
然后修改网关服务
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/688c595a337f4c24b0ad002c1fda168a.png)
最后调整登录和注册页面的静态资源文件的路径.
注册服务的名称msb-auth,启动对应的服务,测试
登录页面
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/a51ce9f85e4042f182bc8209988b6d95.png)
注册页面
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/810653907e894eb0a3d5667964309e4e.png)
## 4.注册功能
### 4.1 手机验证码
&emsp;&emsp;先处理验证码的页面,使其能够倒数操作
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/fa2899f54403470d81c61e8b9e214ec9.png)
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/4f9b125be7354345a86817493164c07e.png)
JS代码
```javascript
$(function(){
$("#sendCode").click(function(){
if($(this).hasClass("d1")){
// 说明正在倒计时
}else{
// 给指定的手机号发送验证码
timeoutChangeStyle()
}
});
})
var num = 10
function timeoutChangeStyle(){
$("#sendCode").attr("class","d1")
if(num == 0){
// 说明1分钟到了可以再次发送验证码了
$("#sendCode").text("发送验证码")
num= 10;
$("#sendCode").attr("class","")
}else{
setTimeout('timeoutChangeStyle()',1000)
$("#sendCode").text(num+"s后再次发送")
}
num --;
}
```
### 4.2 短信验证接口
&emsp;&emsp;通过阿里云的短信服务来实现。我们直接购买0元15次就可以了。https://www.aliyun.com/
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/57ed73c529b441ecad8a8dd7906d636b.png)
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/e9f4f52eaf3d412cac3c4fb0bcb62638.png)
进入到对应的管理控制台,查看对应的信息
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/803a91dae1444dd5b75ac7b233ab00b2.png)
通过短信供应商提供的相关的编程语言的开发模板开发即可
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/9a048fe06aa648648498444126d5c2ca.png)
供应商提供了对应的HttpUtils工具类我们需要下载保存到我们自己的项目中。
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/5cd7e92a1e064fc9b381e7e42ad2df12.png)
然后封装对应的发送验证码的接口
```java
package com.msb.mall.third.utils;
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 method = "POST";
private String appCode;
/**
* 发送短信验证码
* @param phone 发送的手机号
* @param code 发送的短信验证码
*/
public void sendSmsCode(String phone,String code){
Map<String, String> headers = new HashMap<String, String>();
//最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
headers.put("Authorization", "APPCODE " + appCode);
//根据API的要求定义相对应的Content-Type
headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
Map<String, String> querys = new HashMap<String, String>();
Map<String, String> bodys = new HashMap<String, String>();
bodys.put("content", "code:"+code);
bodys.put("phone_number", phone);
bodys.put("template_id", "TPL_0000");
try {
HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
System.out.println(response.toString());
//获取response的body
//System.out.println(EntityUtils.toString(response.getEntity()));
} catch (Exception e) {
e.printStackTrace();
}
}
}
```
添加对应的属性信息
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/14f2c82e543347339e46cc3c5698d00c.png)
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/1cc1456012214728ae5d3ab3a3cb1a47.png)
### 4.3 短信功能
&emsp;&emsp;然后我们将短信功能串联起来
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/85da38b9837c46e4b7c2f4da43bc8966.png)
#### 4.3.1 third服务
&emsp;&emsp;我们需要在第三方服务中提供对外的接口服务
```java
@RestController
public class SMSController {
@Autowired
private SmsComponent smsComponent;
/**
* 调用短信服务商提供的短信API发送短信
* @param phone
* @param code
* @return
*/
@GetMapping("/sms/sendcode")
public R sendSmsCode(@RequestParam("phone") String phone,@RequestParam("code") String code){
smsComponent.sendSmsCode(phone,code);
return R.ok();
}
}
```
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/df8b549c0a6b4b8781beb8a40acb443c.png)
#### 4.3.2 认证服务
&emsp;&emsp;我们需要在认证服务中通过feign来调用third中提供的短信服务同时给客户端提供访问的接口
```xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
```
放开注解
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/4c43c32eb0684661b6f0fb73bdbf416d.png)
然后声明Feign的接口
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/78d4f48f38254350bde42bc08f873f46.png)
定义对应的Controller
```java
@Controller
public class LoginController {
@Autowired
private ThirdPartFeginService thirdPartFeginService;
@ResponseBody
@GetMapping("/sms/sendCode")
public R sendSmsCode(@RequestParam("phone") String phone){
// 生成随机的验证码
String code = UUID.randomUUID().toString().substring(0, 5);
thirdPartFeginService.sendSmsCode(phone,code);
return R.ok();
}
}
```
#### 4.3.3 客户端
&emsp;&emsp;然后我们需要在页面中通过jQuery的异步提交来发送短信
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/af9d02f2a6a84261b466655b422cf252.png)
#### 4.3.4 验证码存储
&emsp;&emsp;当我们把验证码通过短信的形式发送给你客户手机然后我们需要把手机号和对应的验证码存储起来后面可能会集群部署这时我们把这个信息存在在Redis中。
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/27c5d3fce4164fc2a2b0a128622d3b87.png)
添加配置
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/5566599b09d348c5b5fe6f1e34f0597e.png)
存储数据
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/92d226010da1473b9adbeafb9f6afd6f.png)
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/c27951de26314a01b58aa4c3d7c173a3.png)、
搞定
#### 4.3.5 60秒间隔
&emsp;&emsp;针对验证码发送的间隔必须是60秒以上这时我们可以在保存到Redis中的数据的值我们加上发送的时间来处理
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/79b53c42da944421a67bde1c6602f4df.png)
模板页面也需要做出对应的处理
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/21ef90379a8e4f56b7b8c555463c074a.png)
### 4.4 注册数据验证
&emsp;&emsp;表单提交的注册数据我们通过JSR303来验证。
首先定义VO对象
```java
package com.msb.mall.vo;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
/**
* 注册用户的VO对象
*/
@Data
public class UserRegisterVo {
@NotEmpty(message = "账号不能为空")
@Length(min = 3,max = 15,message = "账号必须是3~15位")
private String userName; // 账号
@NotEmpty(message = "密码不能为空")
@Length(min = 3,max = 15,message = "密码必须是3~15位")
private String password; // 密码
@NotEmpty(message = "手机号不能为空")
@Pattern(regexp = "^[1][3-9][0-9]{9}$",message = "手机号不合法")
private String phone; // 手机号
@NotEmpty(message = "验证码不能为空")
private String code; // 验证码
}
```
然后就是控制器的逻辑代码
```java
@PostMapping("/sms/register")
public String register(@Valid UserRegisterVo vo, BindingResult result, Model model){
if(result.hasErrors()){
// 表示提交的数据不合法
List<FieldError> fieldErrors = result.getFieldErrors();
Map<String,String> map = new HashMap<>();
for (FieldError fieldError : fieldErrors) {
String field = fieldError.getField();
String defaultMessage = fieldError.getDefaultMessage();
map.put(field,defaultMessage);
}
model.addAttribute("error",map);
return "/reg";
}
// 表单提交的注册的数据是合法的
return "redirect:/login.html";
}
```
然后就是页面代码处理
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/1b2053f62c3e412bb7f515fa69647eb4.png)
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/d0a1d66eaa824edc936ac8b914961238.png)
验证码的校验
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/e8895b66d8e449efb410578563a94715.png)
### 4.5 完整的注册功能
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/4f4b98662f5c4a8d89580ffedaff9a46.png)
会员服务处理
控制器
```java
/**
* 会员注册
* @return
*/
@PostMapping("/register")
public R register(@RequestBody MemberReigerVO vo){
try {
memberService.register(vo);
}catch (UsernameExsitException exception){
return R.error(BizCodeEnume.USERNAME_EXSIT_EXCEPTION.getCode(),
BizCodeEnume.USERNAME_EXSIT_EXCEPTION.getMsg());
}catch (PhoneExsitExecption exsitExecption) {
return R.error(BizCodeEnume.PHONE_EXSIT_EXCEPTION.getCode(),
BizCodeEnume.PHONE_EXSIT_EXCEPTION.getMsg());
}catch (Exception e){
return R.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(),
BizCodeEnume.UNKNOW_EXCEPTION.getMsg());
}
return R.ok();
}
```
然后对应的Service
```java
/**
* 完成会员的注册功能
* @param vo
*/
@Override
public void register(MemberReigerVO vo) throws PhoneExsitExecption,UsernameExsitException{
MemberEntity entity = new MemberEntity();
// 设置会员等级 默认值
MemberLevelEntity memberLevelEntity = memberLevelService.queryMemberLevelDefault();
entity.setLevelId(memberLevelEntity.getId()); // 设置默认的会员等级
// 添加对应的账号和手机号是不能重复的
checkUsernameUnique(vo.getUserName());
checkPhoneUnique(vo.getPhone());
entity.setUsername(vo.getUserName());
entity.setMobile(vo.getPhone());
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String encode = encoder.encode(vo.getPassword());
// 需要对密码做加密处理
entity.setPassword(encode);
// 设置其他的默认值
this.save(entity);
}
```
auth服务通过Fegin远程调用
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/aa01b1185c9544058ee838c2ef190e43.png)
远程调用
```java
@PostMapping("/sms/register")
public String register(@Valid UserRegisterVo vo, BindingResult result, Model model){
Map<String,String> map = new HashMap<>();
if(result.hasErrors()){
// 表示提交的数据不合法
List<FieldError> fieldErrors = result.getFieldErrors();
for (FieldError fieldError : fieldErrors) {
String field = fieldError.getField();
String defaultMessage = fieldError.getDefaultMessage();
map.put(field,defaultMessage);
}
model.addAttribute("error",map);
return "/reg";
}else{
// 验证码是否正确
String code = (String)redisTemplate.opsForValue().get(SMSConstant.SMS_CODE_PERFIX + vo.getPhone());
code = code.split("_")[0];
if(!code.equals(vo.getCode())){
// 说明验证码不正确
map.put("code","验证码错误");
model.addAttribute("error",map);
return "/reg";
}else{
// 验证码正确 删除验证码
redisTemplate.delete(SMSConstant.SMS_CODE_PERFIX + vo.getPhone());
// 远程调用对应的服务 完成注册功能
R r = memberFeginService.register(vo);
if(r.getCode() == 0){
// 注册成功
return "redirect:http://msb.auth.com/login.html";
}else{
// 注册失败
map.put("msg",r.getCode()+":"+r.get("msg"));
model.addAttribute("error",map);
return "/reg";
}
}
}
//return "redirect:/login.html";
}
```
完成对应的服务注册
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/72ccce0588b54d758cceba235c8a6957.png)
校验提示
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/8d8794dda80045669cc4684390b1831f.png)
## 5.登录功能
&emsp;&emsp;通过最基础的登录操作来完成登录处理
登录页面处理
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/76135367f5aa49f6b39d8380dd614739.png)
认证服务的处理
```java
/**
* 注册的方法
* @return
*/
@PostMapping("/login")
public String login(LoginVo loginVo , RedirectAttributes redirectAttributes){
R r = memberFeginService.login(loginVo);
if(r.getCode() == 0){
// 表示登录成功
return "redirect:http://msb.mall.com/home";
}
redirectAttributes.addAttribute("errors",r.get("msg"));
// 表示登录失败,重新跳转到登录页面
return "redirect:http://msb.auth.com/login.html";
}
```
会员中心的认证逻辑
```java
@RequestMapping("/login")
public R login(@RequestBody MemberLoginVO vo){
MemberEntity entity = memberService.login(vo);
if(entity != null){
return R.ok();
}
return R.error(BizCodeEnume.USERNAME_PHONE_VALID_EXCEPTION.getCode(),
BizCodeEnume.USERNAME_PHONE_VALID_EXCEPTION.getMsg());
}
```
service中的具体认证处理
```java
@Override
public MemberEntity login(MemberLoginVO vo) {
// 1.根据账号或者手机号来查询会员信息
MemberEntity entity = this.getOne(new QueryWrapper<MemberEntity>()
.eq("username", vo.getUserName())
.or()
.eq("mobile", vo.getUserName()));
if(entity != null){
// 2.如果账号或者手机号存在 然后根据密码加密后的校验来判断是否登录成功
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
boolean matches = encoder.matches(vo.getPassword(), entity.getPassword());
if(matches){
// 表明登录成功
return entity;
}
}
return null;
}
```
## 6.Auth2.0
&emsp;&emsp;OAuth2.0是OAuth协议的延续版本但不向前兼容OAuth 1.0(即完全废止了OAuth1.0)。 OAuth
2.0关注客户端开发者的简易性。要么通过组织在资源拥有者和HTTP服务商之间的被批准的交互动作代表用户要么允许第三方应用代表用户获得访问的权限。
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/bf265974f54e42009080c07f02c9e48b.png)
### 6.1 微博开放平台
地址https://open.weibo.com/
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/0184cecb32ca41fc8a03bae2f00f724a.png)
创建应用
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/8a56466dce7e48019ae77f6eb8511651.png)
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/09d77a9058f246c4a82648081d5124ca.png)
创建后的基本信息:
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/3b571819b4a546e88c37406bb78f54ea.png)
授权设置:
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/8124143526eb46b18082da3c165ac477.png)
社交认证文档:
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/02c7a54d5e754d55a77059ddfbf9a254.png)
微博Web端授权的操作
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/9d5ceaf7ff444687b547dfd86698c4fc.png)
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/853aa396b5d0486b8263170552cc315e.png)
引导用户点击按钮跳转到对应的授权页面
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/f5a2c8dbdf2c4b0bbbe0aece7f353bce.png)
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/a25aa1c7417e4b5492d178e8d4a110b4.png)
点击授权按钮后查看回调接口的code信息
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/43a9e56e2856430c964caae9a566b6d3.png)
获取到了code信息59d62e59e5ead5a4ea89c6f9cf212568
然后根据code信息我们可以去授权服务器获取对应的AccessToken。
```
https://api.weibo.com/oauth2/access_token?client_id=1093598037&client_secret=1085c8de04dee49e9bb110eaf2d3cf62&grant_type=authorization_code&redirect_uri=http://msb.auth.com/success.html&code=59d62e59e5ead5a4ea89c6f9cf212568
```
获取Token信息只支持POST方式提交
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/069e76587c36411393182cb2248d8fd4.png)
在PostMan中通过post方式提交成功获取到了对应的token信息
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/cad96be8aef240e7b067044d49b5fff1.png)
获取到了Token信息后我们就可以去资源服务器获取对象的信息
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/fb7bd6f5b6554e92bad4871fd11074b4.png)
### 6.2 百度开放平台
地址:
Auth2.0操作https://developer.baidu.com/wiki/index.php?title=docs/oauth
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/c084707f697848a08f4db1a944cc966b.png)
创建应用http://developer.baidu.com/console#app/project
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/70348f87ddab4ae19c13ce53f826f5d8.png)
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/72d7dd28ddbc48f3aa6f88b6500b7418.png)
创建完成:
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/52efc675f6c5433a8b789b39748cb01a.png)
引导用户跳转到授权地址:
```url
http://openapi.baidu.com/oauth/2.0/authorize?
response_type=code&
client_id=YOUR_CLIENT_ID&
redirect_uri=YOUR_REGISTERED_REDIRECT_URI&
scope=email&
display=popup
```
地址修改为我们自己的http://openapi.baidu.com/oauth/2.0/authorize?response_type=code&client_id=MmvAkQM7HtrQnKDDhhmTSib5&redirect_uri=http://www.baidu.com&display=popup
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/094f3eb050504ad1b675c1514d504721.png)
获取到的Code信息
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/0a568ca08753443a9bfd425049fa0120.png)
coded789d0160b2fa99bb1f840002569526e
获取到对应的token信息
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/9a06a84c41d340b4b561deaa1341e8b8.png)
Token121.6966ae0e0f3cd19fa36a375489342b08.YmfrSxYqsOt1eUoPzkC60yCsa7W09OmqTbPsuVL.zmdMFg
token访问地址https://openapi.baidu.com/rest/2.0/passport/users/getLoggedInUser?access_token=121.6966ae0e0f3cd19fa36a375489342b08.YmfrSxYqsOt1eUoPzkC60yCsa7W09OmqTbPsuVL.zmdMFg
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/298c717fd5574e61bf5f178084052897.png)
## 7.社交登录实现
### 7.1 code处理
&emsp;&emsp;在后台服务中获取code并对应的获取Token信息
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/d70c0d96fb444d8188ba7f2d0a09e270.png)
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/dcfcc8e51be2461888bf8892cf7e8f86.png)
然后需要同步的调整引入的链接地址:
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/0fcafb42475249eea5de2724be2246a9.png)
### 7.2 获取Token信息
&emsp;&emsp;根据上一步获取的code信息我们可以获取对应的Token信息
```java
@RequestMapping("/oauth/weibo/success")
public String weiboOAuth(@RequestParam("code") String code) throws Exception {
Map<String,String> body = new HashMap<>();
body.put("client_id","1093598037");
body.put("client_secret","1085c8de04dee49e9bb110eaf2d3cf62");
body.put("grant_type","authorization_code");
body.put("redirect_uri","http://msb.auth.com/oauth/weibo/success");
body.put("code",code);
// 根据Code获取对应的Token信息
HttpResponse post = HttpUtils.doPost("https://api.weibo.com"
, "/oauth2/access_token"
, "post"
, new HashMap<>()
, null
, body
);
int statusCode = post.getStatusLine().getStatusCode();
if(statusCode != 200){
// 说明获取Token失败,就调回到登录页面
return "redirect:http://msb.auth.com/login.html";
}
// 说明获取Token信息成功
String json = EntityUtils.toString(post.getEntity());
SocialUser socialUser = JSON.parseObject(json, SocialUser.class);
// 注册成功就需要调整到商城的首页
return "redirect:http://msb.mall.com/home.html";
}
```
### 7.3 登录和注册
&emsp;&emsp;表结构中新增对应的
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/df5d68e8e19e4e67adfcb4eabf4fe310.png)
然后在对应的实体对象中添加对应的属性
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/c6b9d25fd0dd4fe49944716ac908dffd.png)
service中实现注册和登录的逻辑
```java
/**
* 社交登录
* @param vo
* @return
*/
@Override
public MemberEntity login(SocialUser vo) {
String uid = vo.getUid();
// 如果该用户是第一次社交登录,那么需要注册
// 如果不是第一次社交登录 那么就更新相关信息 登录功能
MemberEntity memberEntity = this.getOne(new QueryWrapper<MemberEntity>().eq("social_uid", uid));
if(memberEntity != null){
// 说明当前用户已经注册过了 更新token和过期时间
MemberEntity entity = new MemberEntity();
entity.setId(memberEntity.getId());
entity.setAccessToken(vo.getAccessToken());
entity.setExpiresIn(vo.getExpiresIn());
this.updateById(entity);
// 在返回的登录用户信息中我们同步的也保存 token和过期时间
memberEntity.setAccessToken(vo.getAccessToken());
memberEntity.setExpiresIn(vo.getExpiresIn());
return memberEntity;
}
// 表示用户是第一提交,那么我们就需要对应的来注册
MemberEntity entity = new MemberEntity();
entity.setAccessToken(vo.getAccessToken());
entity.setExpiresIn(vo.getExpiresIn());
entity.setSocialUid(vo.getUid());
// 通过token调用微博开发的接口来获取用户的相关信息
try {
Map<String,String> querys = new HashMap<>();
querys.put("access_token",vo.getAccessToken());
querys.put("uid",vo.getUid());
HttpResponse response = HttpUtils.doGet("https://api.weibo.com"
, "/2/users/show.json"
, "get"
, new HashMap<>()
, querys
);
if(response.getStatusLine().getStatusCode() == 200){
String json = EntityUtils.toString(response.getEntity());
JSONObject jsonObject = JSON.parseObject(json);
String nickName = jsonObject.getString("screen_name");
String gender = jsonObject.getString("gender");
entity.setNickname(nickName);
entity.setGender("m".equals(gender)?1:0);
}
}catch (Exception e){
}
// 注册用户信息
this.save(entity);
return entity;
}
```
### 7.4 登录的串联
在Auth服务中我们需要通过Feign来调用MemberService中的相关服务来完成最后的串联
```java
@RequestMapping("/oauth/weibo/success")
public String weiboOAuth(@RequestParam("code") String code) throws Exception {
Map<String,String> body = new HashMap<>();
body.put("client_id","1093598037");
body.put("client_secret","1085c8de04dee49e9bb110eaf2d3cf62");
body.put("grant_type","authorization_code");
body.put("redirect_uri","http://msb.auth.com/oauth/weibo/success");
body.put("code",code);
// 根据Code获取对应的Token信息
HttpResponse post = HttpUtils.doPost("https://api.weibo.com"
, "/oauth2/access_token"
, "post"
, new HashMap<>()
, null
, body
);
int statusCode = post.getStatusLine().getStatusCode();
if(statusCode != 200){
// 说明获取Token失败,就调回到登录页面
return "redirect:http://msb.auth.com/login.html";
}
// 说明获取Token信息成功
String json = EntityUtils.toString(post.getEntity());
SocialUser socialUser = JSON.parseObject(json, SocialUser.class);
R r = memberFeginService.socialLogin(socialUser);
if(r.getCode() != 0){
// 登录错误
return "redirect:http://msb.auth.com/login.html";
}
String entityJson = (String) r.get("entity");
System.out.println("----------------->" + entityJson);
// 注册成功就需要调整到商城的首页
return "redirect:http://msb.mall.com/home";
}
```
# 二、分布式session
## 1.session问题
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/5919a9909d4246cfa00d3851af823456.png)
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/10a29ff1cd594db3aa7fc593e217dc35.png)
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/654b5e4af3ff44dfabb6127daee5d225.png)
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/27e2467140594f1bbe5b1e3a7075bc81.png)
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/9916772823024deab38f500a28e8eec8.png)
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/7e3963ba44814ea79db8ef376abe509c.png)
## 2.SpringSession整合
&emsp;&emsp;我们通过SpringSession来实现Session的共享Session数据存储在Redis中
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/7a07efc356b94ba1a21e2c646769fda8.png)
SpringSession的操作指南
https://docs.spring.io/spring-session/docs/2.5.6/reference/html5/guides/boot-redis.html
导入相关的依赖
```xml
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
```
设置对应的配置
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/b3f81aef68744b5ea4f82bdce1e1ed44.png)
最后我们需要添加对有的注解,放开操作
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/821a371533ba42838cad825568db77f7.png)
然后在Auth服务和商城首页都整合SpringSession后我们再商城首页可以看到Session的数据注意这儿是手动修改Cookie的域名
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/a3b63318cee24cc889749026b5827f9b.png)
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/e902ee72dfa5419a9444b7840fbdfbfe.png)
## 3.自定义Cookie
&emsp;&emsp;通过自定义Cookie实现session域名的调整
```java
@Configuration
public class MySessionConfig {
/**
* 自定义Cookie的配置
* @return
*/
@Bean
public CookieSerializer cookieSerializer(){
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
cookieSerializer.setDomainName("msb.com"); // 设置session对应的一级域名
cookieSerializer.setCookieName("msbsession");
return cookieSerializer;
}
/**
* 对存储在Redis中的数据指定序列化的方式
* @return
*/
@Bean
public RedisSerializer<Object> redisSerializer(){
return new GenericJackson2JsonRedisSerializer();
}
}
```
## 4.单点登录案例演示
&emsp;&emsp;xxl-sso案例代码地址https://gitee.com/xuxueli0323/xxl-sso?_from=gitee_search
下载下来的代码解压缩后通过idea导入然后修改server和simple中的属性文件同时我们需要在host中设置对应的域名
```txt
127.0.0.1 ssoserver.com
127.0.0.1 msb1.com
127.0.0.1 msb2.com
```
在server的配置文件中修改Redis的服务地址
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/56969019e13b4ad78cbabf2458bd9545.png)
然后在simple中修改server的地址和redis服务的地址
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/189eac1a373d4bc8935d36f5bab1d9e1.png)
然后分别启动服务测试即可
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/fyfile/1462/1650940644078/d13eacf0ffd44e74a56bf65aeb0dcc1f.png)