1. 概述
Auth0 是一个成熟的第三方身份认证与授权平台,支持多种应用类型,包括原生应用、单页应用(SPA)和 Web 应用。它提供了开箱即用的功能,比如:
✅ 单点登录(SSO)
✅ 社交登录(如 Google、GitHub)
✅ 多因素认证(MFA)
✅ 用户自注册与管理
本文将带你一步步在 Spring Boot 项目中集成 Auth0,结合 Spring Security 实现安全控制。重点覆盖 Auth0 账户配置、Spring Boot 安全配置、登录/登出流程,以及如何调用 Auth0 管理 API。
⚠️ 注意:本文假设你已有 Spring Security 基础,不赘述基础概念。
2. Auth0 账户配置
2.1. 注册 Auth0 账户
前往 Auth0 官网注册 一个免费账户。免费版支持最多 7000 名活跃用户,不限登录次数,足够用于学习和中小型项目。
2.2. 进入控制台
注册并登录后,你会看到 Auth0 仪表盘,展示登录活动、最新登录记录等信息。
2.3. 创建新应用
在左侧菜单选择 Applications → Create Application。
创建时注意选择应用类型:
✅ Regular Web Applications(适用于 Spring Boot 这类服务端渲染应用)
❌ Native Apps / Single-Page Apps / Machine to Machine Apps(不适用)
2.4. 配置应用回调地址
创建完成后,进入应用设置页,配置以下 URI:
- Allowed Callback URLs:
http://localhost:8080/callback
- Allowed Logout URLs:
http://localhost:8080/
这些是 Auth0 在认证完成后回调你的应用的地址。
2.5. 获取客户端凭证
记下以下三个关键信息,后续配置 Spring Boot 会用到:
- Domain:
dev-example.auth0.com
- Client ID:
your-client-id-here
- Client Secret:
your-client-secret-here
⚠️ 踩坑提示:Client Secret 非常敏感,不要提交到代码仓库。
3. Spring Boot 项目配置
3.1. Maven 依赖
引入 Auth0 提供的 mvc-auth-commons
依赖,简化 OpenID Connect 集成:
<dependency>
<groupId>com.auth0</groupId>
<artifactId>mvc-auth-commons</artifactId>
<version>1.2.0</version>
</dependency>
3.2. Gradle 依赖
如果你用 Gradle:
compile 'com.auth0:mvc-auth-commons:1.2.0'
3.3. application.properties
将 Auth0 凭证写入配置文件:
com.auth0.domain=dev-example.auth0.com
com.auth0.clientId=your-client-id-here
com.auth0.clientSecret=your-client-secret-here
3.4. AuthConfig 配置类
创建安全配置类,启用 Spring Security 并定义访问规则:
@Configuration
@EnableWebSecurity
public class AuthConfig {
@Value("${com.auth0.domain}")
private String domain;
@Value("${com.auth0.clientId}")
private String clientId;
@Value("${com.auth0.clientSecret}")
private String clientSecret;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/callback", "/login", "/").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login")
.and()
.logout().logoutSuccessHandler(logoutSuccessHandler()).permitAll();
return http.build();
}
@Bean
public LogoutSuccessHandler logoutSuccessHandler() {
return new LogoutController(this);
}
}
✅ 关键点:
- 关闭 CSRF(简单示例中可接受)
/login
,/callback
,/
允许匿名访问- 其他请求需认证
- 登出使用自定义
LogoutSuccessHandler
3.5. AuthenticationController Bean
注册 AuthenticationController
,用于生成授权 URL 和处理回调:
@Bean
public AuthenticationController authenticationController() throws UnsupportedEncodingException {
JwkProvider jwkProvider = new JwkProviderBuilder(domain).build();
return AuthenticationController.newBuilder(domain, clientId, clientSecret)
.withJwkProvider(jwkProvider)
.build();
}
📌 原理:JwkProvider
用于从 Auth0 获取公钥,验证 JWT 签名(默认使用 RS256 算法)。
4. AuthController:登录与回调
创建控制器处理登录跳转和 Auth0 回调。
@Controller
public class AuthController {
@Autowired
private AuthConfig config;
@Autowired
private AuthenticationController authenticationController;
}
4.1. 登录接口
@GetMapping("/login")
protected void login(HttpServletRequest request, HttpServletResponse response) {
String redirectUri = "http://localhost:8080/callback";
String authorizeUrl = authenticationController.buildAuthorizeUrl(request, response, redirectUri)
.withScope("openid email")
.build();
response.sendRedirect(authorizeUrl);
}
✅ 说明:
buildAuthorizeUrl
生成 Auth0 登录页跳转链接scope=openid email
表示请求用户身份和邮箱信息
4.2. 回调接口
@GetMapping("/callback")
public void callback(HttpServletRequest request, HttpServletResponse response) {
Tokens tokens = authenticationController.handle(request, response);
DecodedJWT jwt = JWT.decode(tokens.getIdToken());
TestingAuthenticationToken authToken = new TestingAuthenticationToken(
jwt.getSubject(), jwt.getToken()
);
authToken.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(authToken);
response.sendRedirect(config.getContextPath(request) + "/");
}
⚠️ 踩坑:TestingAuthenticationToken
是 Spring Security 的测试用 Token,生产环境建议自定义 AbstractAuthenticationToken
实现。
5. HomeController:主页展示
展示用户信息的主页:
@Controller
public class HomeController {
@GetMapping("/")
@ResponseBody
public String home(Authentication authentication) {
TestingAuthenticationToken token = (TestingAuthenticationToken) authentication;
DecodedJWT jwt = JWT.decode(token.getCredentials().toString());
String email = jwt.getClaims().get("email").asString();
return "Welcome, " + email + "!";
}
}
运行应用:mvn spring-boot:run
访问 http://localhost:8080/login
,跳转至 Auth0 登录页:
登录后显示欢迎信息:
6. 用户注册
6.1. 自注册
Auth0 登录页自带“Sign Up”按钮,用户可自行注册:
6.2. 后台创建用户
也可在 Auth0 控制台手动创建用户:
6.3. 连接方式配置
支持多种登录方式,如数据库认证、社交登录:
支持的社交登录包括:
7. LogoutController:登出功能
实现 LogoutSuccessHandler
,登出时清空会话并跳转 Auth0 注销接口:
@Controller
public class LogoutController implements LogoutSuccessHandler {
private final AuthConfig config;
public LogoutController(AuthConfig config) {
this.config = config;
}
@Override
public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse res,
Authentication authentication) {
if (req.getSession() != null) {
req.getSession().invalidate();
}
String returnTo = "http://localhost:8080/";
String logoutUrl = "https://" + config.getDomain() + "/v2/logout?client_id=" +
config.getClientId() + "&returnTo=" + returnTo;
try {
res.sendRedirect(logoutUrl);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
📌 注意:登出必须调用 Auth0 的 /v2/logout
接口,否则单点登录状态未清除。
8. 调用 Auth0 管理 API
8.1. 创建 Machine to Machine 应用
在 Auth0 控制台创建一个 Machine to Machine Application,用于调用管理 API:
8.2. 授权管理 API 权限
为该应用授予 read:users
和 create:users
权限:
8.3. 获取客户端凭证
记录新应用的 Client ID 和 Secret:
8.4. 获取管理 API Token
使用客户端凭证模式获取访问令牌:
public String getManagementApiToken() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
JSONObject requestBody = new JSONObject();
requestBody.put("client_id", "mgmt-client-id");
requestBody.put("client_secret", "mgmt-client-secret");
requestBody.put("audience", "https://dev-example.auth0.com/api/v2/");
requestBody.put("grant_type", "client_credentials");
HttpEntity<String> request = new HttpEntity<>(requestBody.toString(), headers);
RestTemplate restTemplate = new RestTemplate();
Map<String, String> result = restTemplate.postForObject(
"https://dev-example.auth0.com/oauth/token", request, Map.class);
return result.get("access_token");
}
📌 关键参数:
audience
: 必须是https://{domain}/api/v2/
grant_type
:client_credentials
8.5. UserController:获取用户列表
@Controller
public class UserController {
@GetMapping("/users")
@ResponseBody
public ResponseEntity<String> users() {
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + getManagementApiToken());
HttpEntity<String> entity = new HttpEntity<>(headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> result = restTemplate.exchange(
"https://dev-example.auth0.com/api/v2/users",
HttpMethod.GET, entity, String.class);
return result;
}
}
访问 http://localhost:8080/users
返回用户列表:
[{
"created_at": "2020-05-05T14:38:18.955Z",
"email": "user@example.com",
"email_verified": true,
"identities": [{
"user_id": "5eb17a5a1cc1ac0c1487c37f78758",
"provider": "auth0",
"connection": "Username-Password-Authentication",
"isSocial": false
}],
"name": "user@example.com",
"nickname": "ansh",
"logins_count": 64
}]
8.6. 创建用户
@GetMapping("/createUser")
@ResponseBody
public ResponseEntity<String> createUser() {
JSONObject request = new JSONObject();
request.put("email", "newuser@example.com");
request.put("given_name", "Norman");
request.put("family_name", "Lewis");
request.put("connection", "Username-Password-Authentication");
request.put("password", "Pa33w0rd");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + getManagementApiToken());
HttpEntity<String> entity = new HttpEntity<>(request.toString(), headers);
RestTemplate restTemplate = new RestTemplate();
return restTemplate.postForEntity(
"https://dev-example.auth0.com/api/v2/users", entity, String.class);
}
成功创建后返回用户详情:
{
"created_at": "2020-05-10T12:30:15.343Z",
"email": "newuser@example.com",
"email_verified": false,
"family_name": "Lewis",
"given_name": "Norman",
"identities": [{
"connection": "Username-Password-Authentication",
"user_id": "5eb7f3d76b69bc0c120a8901576",
"provider": "auth0",
"isSocial": false
}],
"name": "newuser@example.com",
"nickname": "norman.lewis"
}
✅ 扩展:通过管理 API 还可操作连接、客户端、规则等资源。
9. 总结
本文完整演示了 Spring Boot + Spring Security + Auth0 的集成方案,涵盖:
- Auth0 应用配置与凭证管理
- 登录、回调、登出流程实现
- 使用
TestingAuthenticationToken
快速集成(生产建议自定义) - 调用 Auth0 管理 API 实现用户 CRUD
所有代码示例已上传至 GitHub:https://github.com/eugenp/tutorials/tree/master/spring-security-modules/spring-security-auth0
💡 建议:生产环境应使用 Spring Security OAuth2 Client 或 Spring Security 6 的新特性,避免直接操作 SecurityContextHolder
。