¶ Spring Security 集成 Authing OIDC 快速开始
本文以 Spring 生态中用于提供认证及访问权限控制的 Spring Security 5 为例,详细介绍 Spring Security 5 如何接入 Authing OIDC
Spring Security 是一个提供安全访问控制解决方案的安全框架。它提供了一组可以在 Spring 应用上下文中配置的 Bean,充分利用了 Spring IOC(控制反转)、DI(依赖注入)和 AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,增强了企业系统的安全性,也减轻了编写大量重复代码的负担。
Spring Security 的主要功能主要包括:
- 认证
- 授权
- 攻击防护
¶ 集成介绍
Authing OIDC 允许客户端根据授权服务器执行的身份验证来验证最终用户的身份,并以可互操作和类似 REST 的方式获取有关最终用户的基本配置文件信息。
允许所有类型的客户端(包括基于 Web 的客户端、移动客户端和 JavaScript 客户端)请求和接收有关经过身份验证的会话和最终用户的信息。规范套件是可扩展的,允许参与者在对他们有意义的时候使用可选功能,例如身份数据加密、OpenID 提供者的发现和会话管理。允许应用程序和站点开发人员对用户进行身份验证,而无需承担存储和管理密码的责任,因为互联网上充斥着大量试图为了自己的利益而破坏用户账户的人。
它简单、可靠、安全,并且可以让他们摆脱存储和管理他人密码的困难和危险工作。还有一个额外的好处是,它还使用户的注册过程更轻松,从而减少了用户跳出率。 利用 Authing OIDC 服务作为用户认证中心的统一入口,使所有需要登录的地方都交给 OIDC 服务来做。简单来说就是把需要进行用户认证的部分都剥离出来交给 OIDC 认证中心来完成。
下面以 Authing 提供的 OIDC 服务为例,将详细介绍使用 Spring Security 5 集成 Authing OIDC 单点登录的方法
¶ 项目搭建
¶ 开发环境
- 开发工具:IDEA
- 项目管理工具:Maven
- JDK版本:1.8
- 版本控制工具:Git
¶ 使用 Spring Initializr 快速构建项目
打开 IDEA,点击 New Project 创建一个新项目,选择 Spring Initializr 创建一个 Spring Boot 项目,输入项目的 Group 以及 Artifact 信息
添加 Spring Web, Spring Security 依赖
另外,集成过程中需要在 pom.xml 中添加一些其他的依赖包,如下:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
¶ 使用 maven 工具构建项目
打开 IDEA,点击 New Project 创建一个新项目,选择 maven 创建一个 maven 项目,然后点击 Next,填写项目名称,最后 Finish 即可
接下来在 pom.xml 中添加父工程依赖和集成过程中需要的其它依赖包
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
🎉🎉🎉至此,你已经完成了 使用 Spring Initializr 和 maven 两种方式构建项目,请选择一种适合自己项目开发的方式即可
¶ 测试项目
创建好项目后,在 IDEA 中运行项目
在项目运行后,使用浏览器访问 http://localhost:8080
会自动跳转到 /login
路由,可以看到页面上出现了一个基础的登录表单,说明项目初始化成功。
¶ 配置 Authing
¶ 获取 Authing 平台信息
首先要在 Authing 注册一个账号,然后进入控制台,按照引导步骤新建一个用户池。
点击左侧的「应用」 菜单项,在右侧会看到一个默认创建好的应用。
点击「配置」,看到 App ID、App Secret 和 Issuer url,请妥善保存,之后会用到这些信息。
然后需要在回调地址处添加 http://localhost:8080/callback
之后的选项与下图中保持一致。
最后还需要在授权配置中,勾选如下的配置,以确保该应用支持的授权模式和 token 的安全配置
¶ 配置项目中的配置文件
找到 src/main/resources/application.properties
,将其重命名为 application.yml
,并添加如下内容:
spring:
security:
oauth2:
client:
registration:
authing:
client-id: {替换为你的App ID如:App Secret5e72d72e3798fb03e1d57b13}
client-secret: {替换为你的App Secret如:931f19ce2161e5560c072f586c706ee6}
redirect-uri: {替换为登录的回调地址 如http://localhost:8080/callback}
client-authentication-method: post
scope:
- openid
- profile
provider:
authing:
issuer-uri: {替换为你的Issuer,如:https://authing-net-sdk-demo.authing.cn/oidc}
user-name-attribute: preferred_username
需要将这里的 {clientId}、{secret}、{issuerUrl} 替换成上一步 应用配置 中的实际信息
¶ 自动回调接口编码
在编写回调接口前,我们需要先配置一个配置类,因为 Spring Security 框架默认会对所有的接口进行拦截,我们需要配置我们回调的接口不受拦截,进行放行,以此来进行接口的回调处理
在项目下新建一个 package,然后新建一个 SpringSecurityConfig 类,此配置类作用是对指定接口进行放行
package cn.authing.springsecurityoidc.config;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import static org.springframework.security.config.Customizer.withDefaults;
@EnableWebSecurity(debug = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//注意此处 callback 是在官网配置的回调地址后缀
http.formLogin().disable();
http.csrf().and().cors().disable();
http.authorizeRequests()
.mvcMatchers("callback","")
.permitAll()
.anyRequest().authenticated();
// 授权码模式回调
http.oauth2Login(withDefaults());
// 密码模式及客户端模式
// http.oauth2Login().loginPage("/loginByPassword").loginProcessingUrl("callback");
}
}
接下来,在项目下新建另外一个 package,然后新建一个 CallBackController 类,此接口作用是登录成功后,回调 Authing 控制台配置的回调地址,以此来获取用户 Token 信息。 注意,下面的参数都是 Authing OIDC 的标准,不能乱改,这也是标准协议的规定,参数所对应的值也就是之前在 Authing 平台应用所配置的那些
package cn.authing.springsecurityoidc.controller;
import cn.hutool.http.HttpUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class CallBackController {
@GetMapping("/callback")
public String getTokenByCode(String code){
Map<String,Object> paramMap = new HashMap<>();
paramMap.put("code",code);
paramMap.put("client_id","{替换为你的 client_id 如:61319680ea8b30c9ca9ca071}");
paramMap.put("client_secret","{替换为你的 client-secret 如:cc8a53d7e22ce6b845330ced6cc5d9f2}");
paramMap.put("grant_type","authorization_code");
paramMap.put("redirect_uri","{替换为你的 redirect-uri 如http://localhost:8080/callback}");
String result = HttpUtil.post("https://cjtjls-demo.authing.cn/oidc/token", paramMap);
return result;
}
}
¶ 运行项目
一切准备就绪了,现在启动项目并访问 http://localhost:8080
,即可看到 Authing 登录窗口
Spring Security 默认会保护首页,在访问首页时会进行认证,未认证的访问请求会跳转到 /login
。 注册并登录后,会跳转回首页,此时可以看到页面上的欢迎语显示了当前登录用户的用户名
登录成功后,会自动回调到我们之前的回调地址(即我们在上面所写的 CallbackController),Authing 会返回以下信息
恭喜 🎉,到此你已经学会了 Spring Security 5 集成 Authing OIDC 认证授权
¶ 其他知识学习
¶ 什么是 OIDC
看一下官方的介绍 http://openid.net/connect/ (opens new window)
OpenID Connect 1.0 is a simple identity layer on top of the OAuth 2.0 protocol. It allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server, as well as to obtain basic profile information about the End-User in an interoperable and REST-like manner.
OpenID Connect allows clients of all types, including Web-based, mobile, and JavaScript clients, to request and receive information about authenticated sessions and end-users. The specification suite is extensible, allowing participants to use optional features such as encryption of identity data, discovery of OpenID Providers, and session management, when it makes sense for them.
简单来说:OIDC 是 OpenID Connect 的简称,OIDC = (Identity, Authentication) + OAuth 2.0。它在 OAuth 上构建了一个身份层,是一个基于 OAuth 协议的身份认证标准协议。我们都知道 OAuth 是一个授权协议,它无法提供完善的身份认证功能,OIDC 使用 OAuth 的授权服务器来为第三方客户端提供用户的身份认证,并把对应的身份认证信息传递给客户端,且可以适用于各种类型的客户端(比如服务端应用、移动 APP、JS 应用),且完全兼容 OAuth,也就是说你搭建了一个 OIDC 的服务后,也可以当作一个 OAuth 的服务来用。应用场景如图:
¶ OIDC 协议族
OIDC 本身是有多个规范构成,其中包含一个核心的规范,多个可选支持的规范来提供扩展支持,简单的来看一下:
- Core:必选。定义 OIDC 的核心功能,在 OAuth 2.0 之上构建身份认证,以及如何使用 Claims 来传递用户的信息。
- Discovery:可选。发现服务,使客户端可以动态的获取 OIDC 服务相关的元数据描述信息(比如支持那些规范,接口地址是什么等等)。
- Dynamic Registration:可选。动态注册服务,使客户端可以动态的注册到 OIDC 的 OP(这个缩写后面会解释)。
- OAuth 2.0 Multiple Response Types:可选。针对 OAuth 2.0 的扩展,提供几个新的 response_type。
- OAuth 2.0 Form Post Response Mode:可选。针对 OAuth 2.0 的扩展,OAuth 2.0 回传信息给客户端是通过 URL 的 querystring 和 fragment 这两种方式,这个扩展标准提供了一基于 form 表单的形式把数据 post 给客户端的机制。
- Session Management:可选。Session 管理,用于规范 OIDC 服务如何管理 Session 信息。
- Front-Channel Logout:可选。基于前端的注销机制,使得 RP(这个缩写后面会解释)可以不使用 OP 的 iframe 来退出。
- Back-Channel Logout:可选。基于后端的注销机制,定义了 RP 和 OP 直接如何通信来完成注销。
¶ OIDC 核心概念
OAuth 2.0 提供了 Access Token 来解决授权第三方客户端访问受保护资源的问题,OIDC 在这个基础上提供了 ID Token 来解决第三方客户端标识用户身份认证的问题。OIDC 的核心在于在 OAuth 2.0 的授权流程中,一并提供用户的身份认证信息(ID Token)给到第三方客户端,ID Token 使用 JWT 格式来包装,得益于 JWT 的自包含性,紧凑性以及防篡改机制,使得 ID Token 可以安全的传递给第三方客户端程序并且容易被验证。此外还提供了 UserInfo 的接口,用户获取用户的更完整的信息。
¶ OIDC 主要术语
主要的术语以及概念介绍
- EU:一个人类用户
- RP:用来代指 OAuth 2.0 中的受信任的客户端,身份认证和授权信息的消费方
- OP:有能力提供 EU 认证的服务(比如 OAuth 2.0 中的授权服务),用来为 RP 提供 EU 的身份认证信息
- ID Token:JWT 格式的数据,包含 EU 身份认证的信息
- UserInfo Endpoint:用户信息接口(受 OAuth 2.0 保护),当 RP 使用 Access Token 访问时,返回授权用户的信息,此接口必须使用 HTTPS
¶ OIDC 工作流程
抽象的角度来看,OIDC 的流程由以下 5 个步骤构成:
- RP 发送一个认证请求给 OP
- OP 对 EU 进行身份认证,然后提供授权
- OP 把 ID Token 和 Access Token(需要的话)返回给 RP
- RP 使用 Access Token 发送一个请求 UserInfo EndPoint
- UserInfo EndPoint 返回 EU 的 Claims
¶ 接下来你可能需要
使用 Spring Security 集成 OAuth 2.0
Spring Security 集成 Authing OAuth 2.0 快速开始Express 学习
Express 集成 OIDC 单点登录指南使用 Spring Security 集成 CAS
Spring Security 集成 Authing CAS 快速开始