Spring Security + OAuth2
第一章 Spring Security 快速入门
第二章 Spring Security 自定义配置
第三章 Spring Security 前后端分离配置
第四章 Spring Security 身份认证
第五章 Spring Security 授权
第六章 OAuth2
文章目录
- Spring Security + OAuth2
- 1、OAuth2简介
- 1.1、OAuth2是什么
- 1.2、OAuth2的角色
- 1.3、OAuth2的使用场景
- 开放系统间授权
- 社交登录
- 开放API
- 现代微服务安全
- 微服务安全
- 企业内部应用认证授权
- 1.4、OAuth2的四种授权模式
- 第一种方式:授权码
- 第二种方式:隐藏式
- 第三种方式:密码式
- 第四种方式:凭证式
- 2、Spring中的OAuth2
- 2.1、相关角色
- 2.2、Spring 中的实现
- 2.3、相关依赖
- 2.4、授权登录的实现思路
- 3、Github 社交登录案例
- 3.1、创建应用
- 3.2、创建测试项目
- 创建项目
- 配置application.yml
- 编写代码
- 启动项目
- 4、案例分析
- 4.1、登录流程
- 4.2、CommonOAuth2Provider
1、OAuth2简介
1.1、OAuth2是什么
“Auth”表示“授权”Authorization
"O"是Open的简称,表示“开放”
连在一起就表示“开发授权”,OAuth2是一种开放授权协议
在实际流程中,颁发Token前先要征询用户同意
1.2、OAuth2的角色
OAuth2.0 协议包含以下角色:
- 资源所有者(Resource Owner):即用户,资源的拥有人,想要通过客户应用访问资源服务器上的资源。
- 客户应用(Client): 通常一个Web或者无线应用,它需要访问用户的受保护资源
- 资源服务器:(Resource Server):存储受保护资源的服务器或定义了可以访问到资源的API,接收并验证客户端的访问令牌,以决定是否授权访问资源。
- 授权服务器(Authorization Server):负责验证资源所有者的身份并向客户端颁发访问令牌。
1.3、OAuth2的使用场景
开放系统间授权
社交登录
在传统的身份验证中,用户需要提供用户名和密码,还有很多网站登录时,允许使用第三方网站的身份,这称为“第三方登录”。所谓第三方登录,实质就是OAuth授权。用户想要登录A网站,A网站让用户提供第三方网站的数据,证明自己的身份。获取第三方网站的身份数据,就需要OAuth授权。
开放API
例如云冲印服务的实现
现代微服务安全
微服务安全
企业内部应用认证授权
- SSO:Single Sign On 单点登录
- IAM:Identity and Access Management 身份识别与访问管理。
1.4、OAuth2的四种授权模式
阮一峰的网络日志-OAuth 2.0 的四种方式
- 授权码
- 隐藏式
- 密码式
- 客户端凭证
第一种方式:授权码
授权码(authorization code),指的是第三方应用先申请一个授权码,然后再用该码获取令牌
这种方式是最常用,最复杂,也是最安全的,它适用于那些有后端的Web应用。授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成。这样的前后端分离,可以避免令牌泄露。
第二种方式:隐藏式
隐藏式,有些web应用是纯前端应用,没有后端。这时就不能用上面的方式了,必须将令牌存在前端。
RFC 6749规定了这种方式,允许直接向前端颁发令牌。这种方式没有授权码这个中间步骤,所以称为隐藏式。
第三种方式:密码式
密码式(password): 如果你高度信任某个应用,RFC 6749也允许用户名和密码,直接告诉该应用。该应用就使用你的密码,申请令牌。
这种方式需要用户给出自己的用户名/密码,显然风险很大,因此只适用于其他授权方式都无法采用的情况,而且必须是用户高度信任的应用。
第四种方式:凭证式
凭证式:适用于没有前端的命令行应用,即在命令行下请求令牌。
这种方式给出的令牌,是针对第三方应用的,而不是针对用户的,即有可能多个用户共享同一个令牌。(示意图和第二种相同)
2、Spring中的OAuth2
2.1、相关角色
回顾:OAuth 2中的角色
- 资源所有者(Resource Owner)
- 客户应用(Client)
- 资源服务器(Resource Server)
- 授权服务器(Authorization Server)
2.2、Spring 中的实现
Spring Security
- 客户应用(OAuth2 Client): OAuth2 客户端功能中包含OAuth2 Login
- 资源服务器(OAuth2 Resource Server)
Spring
- 授权服务器(Spring Authorization Server): 它是在Spring Security 之上的一个单独的项目。
2.3、相关依赖
<!-- 资源服务器 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<!-- 客户应用 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<!-- 授权服务器 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
</dependency>
2.4、授权登录的实现思路
3、Github 社交登录案例
3.1、创建应用
注册客户应用
登录Github,在开发者设置中找到OAuth Apps,创建一个application,为客户应用创建访问Github的凭证:
输入如下信息,点击注册。
创建完成后,用记事本保存一下Client ID
然后需要创建一个Client secrets,同样用记事本保存一下Client secrets
3.2、创建测试项目
创建项目
官网例子
创建一个springboot项目oauth2-login-demo,创建时引入如下依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-oauth2-client</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></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.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-springsecurity6</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-test</artifactId><scope>test</scope></dependency>
配置application.yml
由官网例子可知Github授权服务的配置方式,按照该格式配置即可。
将记事本上保持的Client的id和secret写到yml。
spring:security:oauth2:client:registration:github:client-id: Ov23liHY95uZL4eT7WcQclient-secret: 805cee30396008806a1b63d35caaabed2c7a1eb2
编写代码
该节代码均来自官网例子
新建Controller
@Controller
public class OAuth2LoginController {@GetMapping("/")public String index(Model model, @RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient authorizedClient,@AuthenticationPrincipal OAuth2User oauth2User) {model.addAttribute("userName", oauth2User.getName());model.addAttribute("clientName", authorizedClient.getClientRegistration().getClientName());model.addAttribute("userAttributes", oauth2User.getAttributes());return "index";}
}
新建Index
官网代码
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head><title>Spring Security - OAuth 2.0 Login</title><meta charset="utf-8"/>
</head>
<body>
<div style="float: right" th:fragment="logout" sec:authorize="isAuthenticated()"><div style="float:left"><span style="font-weight:bold">User: </span><span sec:authentication="name"></span></div><div style="float:none"> </div><div style="float:right"><form action="#" th:action="@{/logout}" method="post"><input type="submit" value="Logout"/></form></div>
</div>
<h1>OAuth 2.0 Login with Spring Security</h1>
<div>You are successfully logged in <span style="font-weight:bold" th:text="${userName}"></span>via the OAuth 2.0 Client <span style="font-weight:bold" th:text="${clientName}"></span>
</div>
<div> </div>
<div><span style="font-weight:bold">User Attributes:</span><ul><li th:each="userAttribute : ${userAttributes}"><span style="font-weight:bold" th:text="${userAttribute.key}"></span>: <spanth:text="${userAttribute.value}"></span></li></ul>
</div>
</body>
</html>
启动项目
访问http://localhost:8080/login
点击Github。
4、案例分析
4.1、登录流程
- A网站让用户跳转到GitHub,并携带参数ClientID 以及 Redirection URI。
- GitHub要求用户登录,然后询问用户"A网站要求获取用户信息的权限,你是否同意?"
- 用户同意,GitHub就会重定向回A网站,同时发回一个授权码。
- A网站使用授权码,向GitHub 请求令牌。
- GitHub 返回令牌.
- A网站使用令牌,向GitHub 请求用户数据。
- GitHub返回用户数据
- A网站使用GitHub用户数据登录
4.2、CommonOAuth2Provider
CommonOAuth2Provider是一个预定义的通用OAuth2Provider,为一些知名资源服务API提供商(如Google、GitHub、Facebook)预定义了一组默认的属性。
例如,授权URI、令牌URI和用户信息URI通常不经常变化。因此,提供默认值以减少所需的配置。
因此,当我们配置GitHub客户端时,只需要提供client-id和client-secret属性。
GITHUB {public ClientRegistration.Builder getBuilder(String registrationId) {ClientRegistration.Builder builder = this.getBuilder(registrationId, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, "{baseUrl}/{action}/oauth2/code/{registrationId}");builder.scope(new String[]{"read:user"});builder.authorizationUri("https://github.com/login/oauth/authorize");builder.tokenUri("https://github.com/login/oauth/access_token");builder.userInfoUri("https://api.github.com/user");builder.userNameAttributeName("id");builder.clientName("GitHub");return builder;}},