1. 概述
Auth0 提供用於各種類型的應用程序(如原生應用、單頁面應用和 Web 應用)的 身份驗證和授權服務。 此外,它還允許您實施各種功能,例如單點登錄、社交登錄和多因素身份驗證。
在本教程中,我們將通過分步指南探索 Spring Security 與 Auth0 的集成,並涵蓋 Auth0 賬户的關鍵配置。
2. 設置 Auth0
Auth0 是一個流行的身份驗證即服務 (IDaaS) 平台,可以輕鬆地將身份驗證功能集成到您的應用程序中。 本指南將指導您完成 Auth0 的設置過程。
安裝 Auth0
-
創建 Auth0 帳户: 首先,您需要創建一個 Auth0 帳户。 您可以在 https://auth0.com/ 註冊。
-
創建應用: 在您的 Auth0 儀表板中,創建一個新的應用程序。 這將允許您管理您的應用程序的身份驗證設置。
-
配置應用程序設置: 配置應用程序設置,例如應用程序名稱、域名和應用程序類型。
-
安裝 Auth0 JavaScript 客户端庫: 根據您的應用程序類型,安裝 Auth0 JavaScript 客户端庫。 例如,對於 Web 應用程序,您可以使用 npm 安裝:
npm install auth0-spa-js或者,對於 React 應用程序,可以使用以下命令:
npx create-auth0-react這將會創建一個包含 Auth0 集成配置的 React 項目。
-
配置 Auth0 應用程序設置: 在 Auth0 儀表板中,配置您的應用程序的身份驗證設置,例如客户端 ID 和客户端密鑰。 這些值將用於在您的應用程序中配置 Auth0 集成。
-
集成 Auth0 到您的應用程序: 使用 Auth0 提供的 SDK 或 API,將 Auth0 集成到您的應用程序中。 這通常涉及在您的應用程序中添加 Auth0 JavaScript 客户端庫,並使用 SDK 或 API 來處理身份驗證流程。
// 示例:使用 Auth0-spa-js 登錄 const auth0 = require('auth0-spa-js'); auth0.extend({ // ... 您的 Auth0 配置 }); auth0.authorize({ redirect_uri: 'YOUR_REDIRECT_URI', response_type: 'token', scope: 'openid profile email' });
2.1. 使用 Auth0 註冊
首先,我們將 註冊一個免費的 Auth0 計劃,該計劃可為最多 7000 名活躍用户提供無限登錄權限。 但是,如果已經擁有一個,則可以跳過此部分:
2.2. 儀表盤
登錄到 Auth0 賬户後,您將看到一個儀表盤,它會突出顯示諸如登錄活動、最新登錄和新註冊用户的詳細信息:
2.3. 創建新應用程序
然後,從“應用程序”菜單中,我們將創建一個用於 Spring Boot 的新 OpenID Connect (OIDC) 應用程序。
此外,我們將選擇常規 Web 應用程序作為應用程序類型,從可用的選項中選擇,例如本機應用程序、單頁應用程序和機器對機器應用程序:
2.4. 應用程序設置
接下來,我們將配置一些應用程序 URI,例如 回調 URL 和 註銷 URL,指向我們的應用程序:
2.5. 客户端憑據
最後,我們將獲取與我們的應用程序關聯的 域名、客户端 ID 和 客户端密鑰 的值:
請妥善保管這些憑據,因為它們在我們的 Spring Boot 應用程序的 Auth0 設置中是必需的。
3. Spring Boot 應用設置
現在,我們的 Auth0 賬户已準備就緒,並配置了關鍵設置,我們已準備好將 Auth0 安全集成到 Spring Boot 應用中。
3.1. Maven
首先,我們將最新的 mvc-auth-commons Maven 依賴添加到我們的 pom.xml 中:
<dependency>
<groupId>com.auth0</groupId>
<artifactId>mvc-auth-commons</artifactId>
<version>1.2.0</version>
</dependency>3.2. Gradle
同樣地,在使用 Gradle 時,可以在 build.gradle文件中添加 mvc-auth-commons依賴:
compile 'com.auth0:mvc-auth-commons:1.2.0'3.3. application.properties</h3
我們的 Spring Boot 應用需要 客户端 ID 和 客户端密鑰 以啓用 Auth0 賬户的身份驗證。因此,我們將它們添加到 application.properties 文件中:
com.auth0.domain: dev-example.auth0.com
com.auth0.clientId: {clientId}
com.auth0.clientSecret: {clientSecret}3.4. AuthConfig
接下來,我們將創建 AuthConfig 類,用於從 application.properties 文件中讀取 Auth0 屬性:
@Configuration
@EnableWebSecurity
public class AuthConfig {
@Value(value = "${com.auth0.domain}")
private String domain;
@Value(value = "${com.auth0.clientId}")
private String clientId;
@Value(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();
}
}此外,AuthConfig 類配置為通過創建 SecurityFilterChain 豆啓用 Web 安全性。
3.5. AuthenticationController
最後,我們將 AuthenticationController 類作為 Bean 引用添加到我們之前討論的 AuthConfig 類中:
@Bean
public AuthenticationController authenticationController() throws UnsupportedEncodingException {
JwkProvider jwkProvider = new JwkProviderBuilder(domain).build();
return AuthenticationController.newBuilder(domain, clientId, clientSecret)
.withJwkProvider(jwkProvider)
.build();
}在這裏,我們使用了 JwkProviderBuilder 類來構建 AuthenticationController 類的實例。我們將使用它來獲取公鑰以驗證令牌的簽名(默認情況下,令牌使用 RS256 非對稱簽名算法進行簽名)。
此外,authenticationController Bean 提供了一個用於登錄的授權 URL,並處理回調請求。
4. AuthController
接下來,我們將創建用於登錄和回調功能的 AuthController 類:
@Controller
public class AuthController {
@Autowired
private AuthConfig config;
@Autowired
private AuthenticationController authenticationController;
}在這裏,我們已注入了上一節中 AuthConfig 類和 AuthenticationController 控制器的依賴項。
4.1. 登錄
讓我們創建一個 login 方法,允許我們的 Spring Boot 應用驗證用户:
@GetMapping(value = "/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 授權 URL 並重定向到默認的 Auth0 登錄屏幕。
4.2. 回調 (Callback)
一旦用户使用 Auth0 憑據登錄,回調請求將被髮送到我們的 Spring Boot 應用。為此,讓我們創建一個 callback 方法:
@GetMapping(value="/callback")
public void callback(HttpServletRequest request, HttpServletResponse response) {
Tokens tokens = authenticationController.handle(request, response);
DecodedJWT jwt = JWT.decode(tokens.getIdToken());
TestingAuthenticationToken authToken2 = new TestingAuthenticationToken(jwt.getSubject(),
jwt.getToken());
authToken2.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(authToken2);
response.sendRedirect(config.getContextPath(request) + "/");
}我們處理了回調請求以獲取 accessToken 和 idToken,它們代表了成功的身份驗證。然後,我們創建了 TestingAuthenticationToken 對象,用於在 SecurityContextHolder 中設置身份驗證。
但是,我們可以創建 AbstractAuthenticationToken 類來實現更友好的自定義實現。
5. HomeController
最後,我們將創建一個 HomeController,併為其設置默認映射,用於應用程序的默認主頁:
@Controller
public class HomeController {
@GetMapping(value = "/")
@ResponseBody
public String home(final Authentication authentication) {
TestingAuthenticationToken token = (TestingAuthenticationToken) authentication;
DecodedJWT jwt = JWT.decode(token.getCredentials().toString());
String email = jwt.getClaims().get("email").asString();
return "Welcome, " + email + "!";
}
}在這裏,我們從 DecodedJWT 對象中提取了 idToken。 此外,我們還從聲明(claims)中獲取用户信息,例如電子郵件。
這就完成了! 我們的 Spring Boot 應用已準備好並帶有 Auth0 安全支持。 讓我們使用 Maven 命令運行我們的應用:
mvn spring-boot:run訪問應用程序至 localhost:8080/login,我們將看到 Auth0 提供的一頁默認登錄頁面:
使用註冊用户憑據登錄後,將顯示包含用户電子郵件地址的歡迎消息:
此外,我們會在默認登錄屏幕上找到“註冊”按鈕(位於“登錄”按鈕旁邊),用於自助註冊。
6. 註冊
6.1. 自注冊
首次使用時,可以通過“註冊”按鈕創建 Auth0 賬户,並提供如電子郵件和密碼等信息:
6.2. 創建用户
或者,我們可以從 Auth0 賬户的 Users 菜單中創建一個新用户:
6.3. 連接設置
此外,我們還可以選擇多種連接類型,例如數據庫和社交登錄,用於我們的 Spring Boot 應用的註冊/登錄:
此外,還提供多種社交連接供您選擇:
7. LogoutController
現在我們已經瞭解了登錄和回調功能,現在可以為我們的 Spring Boot 應用添加註銷功能。
讓我們創建 LogoutController 類,該類實現了 LogoutSuccessHandler 接口:
@Controller
public class LogoutController implements LogoutSuccessHandler {
@Autowired
private AuthConfig 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://dev-example.auth0.com/v2/logout?client_id=" +
config.getClientId() + "&returnTo=" +returnTo;
res.sendRedirect(logoutUrl);
}
}在這裏,onLogoutSuccess方法被覆蓋以調用 Auth0 的 /v2/logout 身份驗證註銷 URL。
8. Auth0 管理 API
此前,我們已經瞭解了 Spring Boot 應用中的 Auth0 安全集成。現在,讓我們在同一應用中與 Auth0 管理 API(系統 API)進行交互。
8.1. 創建新應用程序
首先,要訪問 Auth0 Management API,我們需要在 Auth0 賬户中創建一個 機器對機器應用程序:
8.2. 授權
然後,我們將為 Auth0 Management API 添加授權功能,包括讀取/創建用户權限:
8.3. 客户端憑據
最後,我們將收到 客户端 ID 和 客户端密鑰,以便從我們的 Spring Boot 應用訪問 Auth0 管理應用:
8.4. 訪問令牌
以下我們使用前一節中接收到的客户端憑據,為 Auth0 管理應用程序生成訪問令牌:
public String getManagementApiToken() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
JSONObject requestBody = new JSONObject();
requestBody.put("client_id", "auth0ManagementAppClientId");
requestBody.put("client_secret", "auth0ManagementAppClientSecret");
requestBody.put("audience", "https://dev-example.auth0.com/api/v2/");
requestBody.put("grant_type", "client_credentials");
HttpEntity<String> request = new HttpEntity<String>(requestBody.toString(), headers);
RestTemplate restTemplate = new RestTemplate();
HashMap<String, String> result = restTemplate
.postForObject("https://dev-example.auth0.com/oauth/token", request, HashMap.class);
return result.get("access_token");
}在這裏,我們向 /oauth/token Auth0 Token URL 發起了 REST 請求,以獲取訪問和刷新令牌。
此外,我們可以在 application.properties 文件中存儲這些客户端憑據,並使用 AuthConfig 類進行讀取。
8.5. UserController
之後,讓我們創建一個 UserController 類,其中包含 users 方法:
@Controller
public class UserController {
@GetMapping(value="/users")
@ResponseBody
public ResponseEntity<String> users(HttpServletRequest request, HttpServletResponse response) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + getManagementApiToken());
HttpEntity<String> entity = new HttpEntity<String>(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;
}
}users 方法通過向生成的上一節中訪問令牌生成的 /api/v2/users Auth0 API 發送 GET 請求,獲取所有用户列表。
因此,讓我們訪問 localhost:8080/users 以接收包含所有用户的 JSON 響應:
[{
"created_at": "2020-05-05T14:38:18.955Z",
"email": "[email protected]",
"email_verified": true,
"identities": [
{
"user_id": "5eb17a5a1cc1ac0c1487c37f78758",
"provider": "auth0",
"connection": "Username-Password-Authentication",
"isSocial": false
}
],
"name": "[email protected]",
"nickname": "ansh",
"logins_count": 64
// ...
}]8.6. 創建用户
類似於創建用户,我們可以通過向 Auth0 API 發送 POST 請求來創建用户:
具體來説,我們向 /api/v2/users Auth0 API 發送 POST 請求。
@GetMapping(value = "/createUser")
@ResponseBody
public ResponseEntity<String> createUser(HttpServletResponse response) {
JSONObject request = new JSONObject();
request.put("email", "[email protected]");
request.put("given_name", "Norman");
request.put("family_name", "Lewis");
request.put("connection", "Username-Password-Authentication");
request.put("password", "Pa33w0rd");
// ...
ResponseEntity<String> result = restTemplate
.postForEntity("https://dev-example.auth0.com/api/v2/users", request.toString(), String.class);
return result;
}然後,讓我們訪問 localhost:8080/createUser 並驗證新用户的詳細信息:
{
"created_at": "2020-05-10T12:30:15.343Z",
"email": "[email protected]",
"email_verified": false,
"family_name": "Lewis",
"given_name": "Norman",
"identities": [
{
"connection": "Username-Password-Authentication",
"user_id": "5eb7f3d76b69bc0c120a8901576",
"provider": "auth0",
"isSocial": false
}
],
"name": "[email protected]",
"nickname": "norman.lewis",
// ...
}同樣,我們還可以使用 Auth0 API 執行各種操作,例如列出所有連接、創建連接、列出所有客户端以及創建客户端,具體操作取決於我們的權限。
9. 結論
在本教程中,我們探討了 Spring Security 與 Auth0 的集成。
首先,我們設置了 Auth0 賬户,並完成了必要的配置。然後,我們創建了一個 Spring Boot 應用,並配置了 application.properties 以進行 Spring Security 與 Auth0 的集成。
接下來,我們研究了創建 Auth0 管理 API 令牌的方法。最後,我們研究了諸如獲取所有用户和創建用户等功能。