本文基於Spring Boot OAuth2,為您介紹OAuth的SDK樣本和相關配置。
前提條件
修改設定檔
參考Spring Boot and OAuth2文檔及樣本,設定檔主要做以下兩點修改。
在專案的src/main/resources目錄下建立application.yml或 application.yaml,它是Spring Boot專案的核心設定檔,具體配置如下。
spring: security: oauth2: client: registration: alibabacloud: client-id: 415195082384692**** client-secret: 6EwN4qutnZuchG6n677Ie33SsjAhwyTpcOMSoIo6v0gqJtw4QcHhERVXfqzc**** client-authentication-method: client_secret_basic authorization-grant-type: authorization_code redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}" client-name: alibabacloud provider: alibabacloud: authorization-uri: https://signin.alibabacloud.com/oauth2/v1/auth token-uri: https://oauth.alibabacloud.com/v1/token user-info-uri: https://oauth.alibabacloud.com/v1/userinfo user-name-attribute: sub jwk-set-uri: https://oauth.alibabacloud.com/v1/keys在pom.xml添加如下依賴配置。
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.18</version> <relativePath /> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.4.1</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>bootstrap</artifactId> <version>4.3.1</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>webjars-locator-core</artifactId> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>js-cookie</artifactId> <version>2.1.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-client</artifactId> </dependency> </dependencies>
完整程式碼範例
後端程式碼範例
基於Spring Security後端架構實現一個安全的Web應用程式,包括處理認證、授權、錯誤處理和CSRF防護。以下樣本中,定義了一個RESTful API控制器WebApplication,該控制器處理HTTP請求並與OAuth2認證系統整合。
定義了一個私人變數handler,這是一個AuthenticationEntryPointFailureHandler的執行個體,用於處理認證進入點失敗的情況。當使用者嘗試訪問需要認證的頁面,但認證失敗時,這個處理器會設定HTTP狀態代碼為401(未授權),並返回"Unauthorized"錯誤訊息。
WebApplication類提供了一個GET映射
/user,這個方法會在使用者訪問/user路徑時被調用。它接收一個OAuth2User對象作為參數,這個對象代表了當前經過認證的使用者的OAuth2資訊。方法返回一個包含使用者名稱的Map對象,使用者名稱是從OAuth2User對象的屬性中擷取的。在configure方法中,WebApplication類配置了HttpSecurity對象,以實現Web應用程式的安全性原則。它首先配置了允許匿名訪問的路徑,包括根路徑
/、錯誤頁面/error和webjars下的資源檔。然後,它配置了對其他所有請求進行身分識別驗證,這意味著只有經過認證的使用者才能訪問這些路徑。configure方法還配置了異常處理,當發生未授權異常時,會返回401狀態代碼,並使用之前定義的handler來處理認證失敗的情況。接下來,configure方法配置了OAuth2登入功能,包括登入失敗的處理。如果登入失敗,會在使用者會話中設定錯誤訊息,並調用handler來處理失敗情況。
configure方法配置了登出功能,設定了登出成功後使用者將被重新導向到根路徑
/,並且這個操作對所有使用者都是允許的。configure方法還配置了CSRF防護,使用CookieCsrfTokenRepository來儲存CSRF令牌,並禁用了HttpOnly屬性,以增加安全性。error方法是一個額外的GET映射,用於處理錯誤請求。它從使用者會話中擷取錯誤訊息,並在返回錯誤訊息之前將其從會話中移除。這樣,錯誤訊息就不會被重複顯示給使用者。
import org.springframework.boot.SpringApplication; import org.springframework.http.HttpStatus; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.web.authentication.AuthenticationEntryPointFailureHandler; import org.springframework.security.web.authentication.HttpStatusEntryPoint; import org.springframework.security.web.csrf.CookieCsrfTokenRepository; import org.springframework.web.bind.annotation.GetMapping; import javax.servlet.http.HttpServletRequest; import java.util.Collections; import java.util.Map; public class WebApplication extends WebSecurityConfigurerAdapter { private AuthenticationEntryPointFailureHandler handler = new AuthenticationEntryPointFailureHandler((request, response, authException) -> response.sendError(401, "Unauthorized")); @GetMapping("/user") public Map<String, Object> user(@AuthenticationPrincipal OAuth2User principal) { return Collections.singletonMap("name", principal.getAttribute("name")); } @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests(a -> a .antMatchers("/", "/error", "/webjars/**").permitAll() .anyRequest().authenticated() ) .exceptionHandling(e -> e .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)) ) .oauth2Login(o -> o .failureHandler((request, response, exception) -> { request.getSession().setAttribute("error.message", exception.getMessage()); handler.onAuthenticationFailure(request, response, exception); }) ) .logout(l -> l .logoutSuccessUrl("/").permitAll() ) .csrf(c -> c .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) ); } @GetMapping("/error") public String error(HttpServletRequest request) { String message = (String) request.getSession().getAttribute("error.message"); if (message != null) { request.getSession().removeAttribute("error.message"); } return message; } }
前端程式碼範例
在專案的src/main/resources/static目錄下建立index.html頁面,以便校正,程式碼範例如下。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<title>Demo</title>
<meta name="description" content=""/>
<meta name="viewport" content="width=device-width"/>
<base href="/"/>
<link rel="stylesheet" href="/webjars/bootstrap/css/bootstrap.min.css"/>
<script src="/webjars/jquery/jquery.min.js"></script>
<script src="/webjars/bootstrap/js/bootstrap.min.js"></script>
<script src="/webjars/js-cookie/js.cookie.js">
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (settings.type === 'POST' || settings.type === 'PUT' || settings.type === 'DELETE') {
if (!(/^(http:\/\/|https:\/\/)/.test(settings.url))) {
xhr.setRequestHeader("X-XSRF-TOKEN", Cookies.get('XSRF-TOKEN'));
}
}
}
});
</script>
</head>
<body>
<h1>Demo</h1>
<div class="container text-danger error"></div>
<script>
$.get("/error", function (data) {
if (data) {
$(".error").html(data);
} else {
$(".error").html('');
}
});
</script>
<div class="container unauthenticated">
With Aliyun: <a href="/oauth2/authorization/aliyun">click here</a>
</div>
<div class="container authenticated">
With Google:<a href="/oauth2/authorization/google">click here</a>
</div>
<script type="text/javascript">
$.get("/user", function(data) {
$("#user").html(data.name);
$(".unauthenticated").hide()
$(".authenticated").show()
});
</script>
<div class="container authenticated">
Logged in as: <span id="user"></span>
<div>
<button onClick="logout()" class="btn btn-primary">Logout</button>
</div>
</div>
<script type="text/javascript">
var logout = function() {
$.post("/logout", function() {
$("#user").html('');
$(".unauthenticated").show();
$(".authenticated").hide();
})
return true;
}
</script>
</body>
</html>結果驗證
運行WebApplication程式碼範例,專案啟動後在瀏覽器中訪問http://localhost:8080。