目录
- 1. 微服务架构下统⼀认证介绍
- 2. 微服务架构下统⼀认证思路
- 3. OAuth2 开放授权协议 / 标准
- 4. Spring Cloud OAuth2 + JWT 的实现
认证:验证⽤户的合法身份,⽐如输⼊⽤户名和密码,系统会在后台验证⽤户名和密码是否合法,合法的前提下,才能够进⾏后续的操作,访问受保护的资源
1. 微服务架构下统⼀认证介绍
分布式系统的每个服务都会有认证需求,如果每个服务都实现⼀套认证逻辑会⾮常冗余,考虑分布式系统共享性的特点,需要由独⽴的认证服务处理系统认证的请求。
2. 微服务架构下统⼀认证思路
2.1 基于 session 的认证⽅式
在分布式的环境下,基于 session
的认证会出现⼀个问题,每个应⽤服务都需要在 session
中存储⽤户身份信息,通过负载均衡将本地的请求分配到另⼀个应⽤,服务需要将 session
信息带过去,否则会重新认证。我们可以使⽤ session 共享、session 黏贴
等⽅案。
session 方案也有缺点,比如基于cookie,移动端不能有效使用等
2.2 基于 token 的认证⽅式
基于 token
的认证⽅式,服务端不⽤存储认证数据,易维护扩展性强, 客户端可以把 token
存在任意地⽅,并且可以实现 web 和 app 统⼀认证机制。
其缺点也很明显,token 由于⾃包含信息,因此⼀般数据量较⼤,⽽且每次请求 都需要传递,因此⽐较占带宽。另外,token 的签名验签操作也会给 cpu 带来额外的处理负担。
3. OAuth2 开放授权协议 / 标准
3.1 OAuth2 相关介绍
OAuth(开放授权)
是⼀个开放协议 / 标准,允许⽤户授权第三⽅应⽤访问他们存储在另外的服务提供者上的信息,⽽不需要将⽤户名和密码提供给第三⽅应⽤或分享他们数据的所有内容。
OAuth2 是 OAuth 协议的延续版本,但不向下兼容 OAuth1 ,即完全废弃了OAuth1
3.2 OAuth2 协议⻆⾊和流程
一个网站要开发使⽤QQ登录这个功能的话,那么该网站是需要提前到QQ平台进⾏登记的
- 网站 > 登记 > QQ平台
- QQ 平台会颁发⼀些参数给该网站,后续上线进⾏授权登录的时候(打开的授权⻚⾯)需要携带这些参数
- client_id:客户端id(QQ最终相当于⼀个认证授权服务器,该网站就相当于⼀个客户端,所以会给⼀个客户端id),相当于账号
- secret:相当于密码
- 资源所有者(Resource Owner):可以理解为⽤户
- 客户端(Client):我们想登陆的⽹站或应⽤
- 认证服务器(Authorization Server):可以理解为微信或者QQ
- 资源服务器(Resource Server):可以理解为微信或者QQ
3.3 什么情况下需要使⽤ OAuth2
-
第三⽅授权登录的场景:
⽐如,我们经常登录⼀些⽹站或者应⽤的时候,可以选择使⽤第三⽅授权登录的⽅式,⽐如:微信授权登录、QQ授权登录、微博授权登录等,这是典型的OAuth2
使⽤场景。 -
单点登录的场景:
如果项⽬中有很多微服务或者公司内部有很多服务,可以专⻔做⼀个认证中⼼(充当认证平台⻆⾊),所有的服务都要到这个认证中⼼做认证,只做⼀次登录,就可以在多个授权范围内的服务中⾃由串⾏。
3.4 OAuth2 颁发 Token授权⽅式
- 授权码(authorization-code)
- 密码式(password)提供⽤户名+密码 换取 token令牌
- 隐藏式(implicit)
- 客户端凭证(client credentials)
授权码模式使⽤到了回调地址,是最复杂的授权⽅式,微博、微信、QQ等第三⽅登录就是这种模式。
4. Spring Cloud OAuth2 + JWT 的实现
4.1 Spring Cloud OAuth2 介绍
Spring Cloud OAuth2
是 Spring Cloud
体系对 OAuth2
协议的实现,可以⽤来做多个微服务的统⼀认证(验证身份合法性)授权(验证权限)。通过向 OAuth2
服务(统⼀认证授权服务)发送某个类型的 grant_type
进⾏集中认证和授权,从⽽获得access_token
(访问令牌),⽽这个 token
是受其他微服务信任的。
注意:使⽤ OAuth2 解决问题的本质是,引⼊了⼀个认证授权层,认证授权层连接了资源的拥有者,在授权层⾥⾯,资源的拥有者可以给第三⽅应⽤授权去访问某些受保护资源。
4.2 Spring Cloud OAuth2 构建微服务统⼀认证服务思路
注意:在统⼀认证的场景中,Resource Server 其实就是各种受保护的微服务,微服务中的各种 API 访问接⼝就是资源,发起 http 请求的浏览器就是 Client 客户端(对应为第三⽅应⽤)
4.3 搭建认证服务器(Authorization Server)
认证服务器(Authorization Server),负责颁发token,新建项目 cloud-oauth-server-9999
- pom.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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>resume-cloud-parent</artifactId>
<groupId>com.study</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-oauth-server-9999</artifactId>
<dependencies>
<!--导⼊Eureka Client依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--导⼊spring cloud oauth2依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.1.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
</dependencies>
</project>
- application.yml
server:
port: 9999
spring:
application:
name: oauth2-server
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka,http://127.0.0.1:8762/eureka
instance:
#使⽤ip注册,否则会使⽤主机名注册了(此处考虑到对⽼版本的兼容,新版本经过实验都是ip)
prefer-ip-address: true
#⾃定义实例显示格式,加上版本号,便于多版本管理,注意是ip-address,早期版本是ipAddress
instance-id: ${
spring.cloud.client.ip-address}:${
spring.application.name}:${
server.port}:@project.version@
- 启动类
package com.study;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author xiaosong
* @version 1.0
* @since 2021/1/5
*/
@SpringBootApplication
@EnableDiscoveryClient
public class OAuthApplication9999 {
public static void main(String[] args) {
SpringApplication.run(OAuthApplication9999.class,args);
}
}
- 认证服务器配置类
package com.study.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import</