Add sign-up & sign-in with Azure Active Directory B2C to a Spring web app
一開始請先建立好Azure AD B2C的服務
- Create Azure B2C tenant
Domain nam、Azure subscription、Resource group
例如:domain name
=cathaybkexample.onmicrosoft.com
- Add an application registration
enter your app’s namespring web app
choose support account typeany IDP(authenticating with user flows)
set the Redirect URIs tohttp://localhost:8080/login/oauth2/code/
- Add app secrets for your app
Select Certificates & secrets(憑證及祕密)
New client secrets.
Copy your client secret value
- Azure AD B2C User flow
Create asign-up and sign-in
user flow
choose the user attributes and claims(使用者屬性和宣告屬性)
Enable self-service password reset(自助式密碼重設 = 忘記密碼)
可在使用者流程中執行測試流程,此步驟會呈現Azure AD B2C的登入頁面
此時服務無法導轉成功是正常的,因為應用程式尚未啟動
以上步驟可參考Microsoft官方文件
Azure AD B2C application
Azure AD B2C User flow
Configure and compile your app
本文使用spring-boot 2.7.11版,搭配spring-cloud-azure 4.x版
- 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.11</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.azure.example</groupId>
<artifactId>azureB2C</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>azureB2C</name>
<description>Azure Active Directory B2C to Spring web app</description>
<properties>
<java.version>17</java.version>
<spring-cloud-azure.version>4.14.0</spring-cloud-azure.version>
</properties>
<dependencies>
<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>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter</artifactId>
</dependency>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter-active-directory-b2c</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</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>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-dependencies</artifactId>
<version>${spring-cloud-azure.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- application.yml
專案中的 src/main/resources 資料夾,編輯 application.yml 檔案
* 注意:client-secret
必須加上單引號(' ')
spring:
cloud:
azure:
active-directory:
b2c:
enabled: true
base-uri: https://<your-tenant-initial-domain-name>.b2clogin.com/<your-tenant-initial-domain-name>.onmicrosoft.com/
credential:
client-id: <your-application-ID>
client-secret: '<secret-value>'
login-flow: sign-up-or-sign-in
# default to sign-up-or-sign-in, will look up the user-flows map with provided key.
logout-success-url: http://localhost:8080/login
user-flows:
profile-edit: B2C_1_profile-edit # 此步驟尚未建立
sign-up-or-sign-in: B2C_1_signupsignin
- Controller
在 src/main/java/<package>/controller 中建立並編輯WebController .java
package com.azure.example.azureB2C.controller;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class WebController {
private void initializeModel(Model model, OAuth2AuthenticationToken token) {
if (token != null) {
final OAuth2User user = token.getPrincipal();
model.addAttribute("grant_type", user.getAuthorities());
model.addAllAttributes(user.getAttributes());
}
}
@GetMapping(value = "/")
public String index(Model model, OAuth2AuthenticationToken token) {
initializeModel(model, token);
return "home";
}
}
- Configuration
在 src/main/java/<package>/security 中建立並編輯WebSecurityConfiguration.java
* 注意: 官方文件(2023/12)中使用的WebSecurityConfigurerAdapter 已在spring-boot 2.7.0被棄用
package com.azure.example.azureB2C.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import com.azure.spring.cloud.autoconfigure.aadb2c.AadB2cOidcLoginConfigurer;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class WebSecurityConfiguration {
private final AadB2cOidcLoginConfigurer configurer;
public WebSecurityConfiguration(AadB2cOidcLoginConfigurer configurer) {
this.configurer = configurer;
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.apply(configurer).and().authorizeHttpRequests().anyRequest().authenticated();
return http.build();
}
}
- home.html (此為登入成功後,授權顯示之頁面)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>Home</title>
</head>
<body>
<h1>Home Page</h1>
<div>
<form style="display:inline" method="get" action="/logout">
<button class="btn btn-md btn-primary btn-block" type="submit">Log out</button>
</form>
<!--form style="display:inline" method="get" action="/oauth2/authorization/B2C_1_profile-edit">
<button class="btn btn-md btn-primary btn-block" type="submit">Profile edit</button>
</form-->
</div>
<div>
<br/>
<h2>Azure Active Directory B2C OIDC Login Successfully.</h2>
<h3>Welcome back <span style="color:cyan" th:text="${name}"></span>!</h3>
<table border="1">
<tr><th>Principal</th><th>Value</th></tr>
<tr><th>name</th><th th:text="${name}"></th></tr>
<tr><th>grant_type</th><th th:text="${grant_type}"></th></tr>
<tr><th>at_hash</th><th th:text="${at_hash}"></th></tr>
<tr><th>sub</th><th th:text="${sub}"></th></tr>
<tr><th>country</th><th th:text="${country}"></th></tr>
<tr><th>ver</th><th th:text="${ver}"></th></tr>
<tr><th>city</th><th th:text="${city}"></th></tr>
<tr><th>postalCode</th><th th:text="${postalCode}"></th></tr>
<tr><th>jobTitle</th><th th:text="${jobTitle}"></th></tr>
<tr><th>iss</th><th th:text="${iss}"></th></tr>
<tr><th>oid</th><th th:text="${oid}"></th></tr>
<tr><th>given_name</th><th th:text="${given_name}"></th></tr>
<tr><th>emails</th><th th:text="${emails}"></th></tr>
<tr><th>aud</th><th th:text="${aud}"></th></tr>
<tr><th>nbf</th><th th:text="${nbf}"></th></tr>
<tr><th>streetAddress</th><th th:text="${streetAddress}"></th></tr>
<tr><th>auth_time</th><th th:text="${auth_time}"></th></tr>
<tr><th>state</th><th th:text="${state}"></th></tr>
<tr><th>exp</th><th th:text="${exp}"></th></tr>
<tr><th>iat</th><th th:text="${iat}"></th></tr>
<tr><th>family_name</th><th th:text="${family_name}"></th></tr>
<tr><th>tfp</th><th th:text="${tfp}"></th></tr>
</table>
</div>
</body>
</html>
Demo
在瀏覽器中輸入 http://localhost:8080
便會跳至授權端點https://<your-tenant-domain-name>.b2clogin.com/<your-tenant-domain-name>.onmicrosoft.com/oauth2/v2.0/authorize
若點選"註冊流程",會根據先前設定的密碼強度作限制,以及向使用者蒐集應用程式方想知道的使用者屬性。
若輸入帳號密碼,完成"登入流程"後,便會 return "home";
此步驟會從token取得使用者資訊,顯示於頁面上
而token可取得哪些資訊,則根據先前設定的宣告屬性。
完成以上操作,就大功告成啦!
㊗️恭喜你成功使用Azure Active Directory B2C 建立註冊/登入流程!
補充: Create a profile editing user flow
若想啟用Profile edit Button,需再新增一個使用者流程
(想新增其他使用者流程,可比照此方法設定)
- Create a
profile-edit
user flow - For User attributes, choose the attributes that you want the customer to be able to edit in their profile.
- application.yml 加上新增的user-flows
spring:
cloud:
azure:
active-directory:
b2c:
user-flows:
profile-edit: B2C_1_profile-edit
- home.html 加上調用/oauth2/authorization/B2C_1_profile-edit 的按鍵
<div>
<form style="display:inline" method="get" action="/oauth2/authorization/B2C_1_profile-edit">
<button class="btn btn-md btn-primary btn-block" type="submit">Profile edit</button>
</form>
</div>
Demo
基礎概念介紹
第三方登入 OpenID
若喜歡我在 Medium 的內容,可以拍個手(Claps)
讓我知道你/妳喜不喜歡這篇文章:
拍 5 下:我們一起加加油👏
拍 10 下:覺得文章內容對你很有幫助