javascript
oidc auth2.0_使用Spring Security 5.0和OIDC轻松构建身份验证
oidc auth2.0
“我喜歡編寫身份驗證和授權代碼。” ?從來沒有Java開發(fā)人員。 厭倦了一次又一次地建立相同的登錄屏幕? 嘗試使用Okta API進行托管身份驗證,授權和多因素身份驗證。
Spring Security不僅是一個功能強大且可高度自定義的身份驗證和訪問控制框架,它還是保護基于Spring的應用程序的實際標準。 從前,Spring Security需要使用大量的XML來配置所有內(nèi)容,但是那段日子已經(jīng)過去了。 如今,Spring Security通過Spring的JavaConfig提供了更簡單的配置。 如果您看一下我最近寫的JHipster OIDC示例中的`SecurityConfiguration.java`類,您會發(fā)現(xiàn)它少于100行代碼!
Spring Security 5.0可以解析400多個票證,并且具有許多新功能 :
- OAuth 2.0登錄
- React性支持: @EnableWebFluxSecurity , @EnableReactiveMethodSecurity和WebFlux測試支持
- 現(xiàn)代化的密碼編碼
今天,我將向您展示如何在Okta中使用OAuth 2.0登錄支持。 我還將向您展示如何通過OpenID Connect(OIDC)檢索用戶的信息。
您知道Okta提供免費的開發(fā)人員帳戶 ,每月最多有7,000個活躍用戶,對嗎? 這應該足以使您的殺手級應用破土動工。
Spring Security使使用OAuth 2.0進行身份驗證變得非常容易。 它還提供了通過OIDC獲取用戶信息的功能。 請按照以下步驟了解更多信息!
什么是OIDC? 如果您不熟悉OAuth或OIDC,建議您閱讀OAuth到底是什么 。 Open ID Connect流涉及以下步驟:
創(chuàng)建一個Spring Boot應用
在瀏覽器中打開start.spring.io 。 Spring Initialzr是一個站點,可讓您快速輕松地創(chuàng)建新的Spring Boot應用程序。 將Spring Boot版本(在右上角)設置為2.0.0.M7 。 輸入組和工件名稱。 從下面的屏幕快照中可以看到,我選擇了com.okta.developer和oidc 。 對于依賴項,選擇Web , Reactive Web , Security和Thymeleaf 。
單擊“ 生成項目” ,下載zip,在硬盤上展開,然后在您喜歡的IDE中打開項目。 使用./mvnw spring-boot:run運行該應用程序, ./mvnw spring-boot:run將提示您登錄。
Spring Security 4.x通過基本身份驗證而不是登錄表單提示您,因此這與Spring Security 5有所不同。
Spring Security啟動程序會創(chuàng)建一個默認用戶,其用戶名為“ user”,并且密碼每次啟動應用程序時都會更改。 您可以在終端中找到該密碼,類似于以下密碼。
Using default security password: 103c55b4-2760-4830-9bca-a06a87d384f9在表單中,為“用戶”輸入“ user”,并為“密碼”輸入生成的密碼。 下一個屏幕將是404,因為您的應用沒有為/路徑配置默認路由。
在Spring Boot 1.x中,您可以更改用戶的密碼,因此每次都通過在src/main/resources/application.properties添加以下內(nèi)容來更改密碼。
security.user.password=spring security is ph@!但是,這是Spring Boot 2.0中不推薦使用的功能。 好消息是,此更改可能會在GA發(fā)布之前恢復 。
同時,您可以將打印的密碼復制到控制臺,并與HTTPie一起使用 。
$ http --auth user:'bf91316f-f894-453a-9268-4826cdd7e151' localhost:8080 HTTP/1.1 404 Cache-Control: no-cache, no-store, max-age=0, must-revalidate Content-Type: application/json;charset=UTF-8 Date: Sun, 03 Dec 2017 19:11:50 GMT Expires: 0 Pragma: no-cache Set-Cookie: JSESSIONID=65283FCBDB9E6EF1C0679290AA994B0D; Path=/; HttpOnly Transfer-Encoding: chunked X-Content-Type-Options: nosniff X-Frame-Options: DENY X-XSS-Protection: 1; mode=block響應也將是404。
{"error": "Not Found","message": "No message available","path": "/","status": 404,"timestamp": "2017-12-03T19:11:50.846+0000" }您可以通過在與OidcApplication.java ( src/main/java/com/okta/developer/oidc )相同的目錄中創(chuàng)建MainController.java來擺脫404。 創(chuàng)建一個home()方法,該方法映射到/并返回用戶名。
package com.okta.developer.oidc;import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;import java.security.Principal;@RestController public class MainController {@GetMapping("/")String home(Principal user) {return "Hello " + user.getName();} }重新啟動服務器,使用user和生成的密碼登錄,您應該看到Hello user 。
$ http --auth user:'d7c4138d-a1cc-4cc9-8975-97f37567594a' localhost:8080 HTTP/1.1 200 Cache-Control: no-cache, no-store, max-age=0, must-revalidate Content-Length: 10 Content-Type: text/plain;charset=UTF-8 Date: Sun, 03 Dec 2017 19:26:54 GMT Expires: 0 Pragma: no-cache Set-Cookie: JSESSIONID=22A5A91051B7AFBA1DC8BD30C0B53365; Path=/; HttpOnly X-Content-Type-Options: nosniff X-Frame-Options: DENY X-XSS-Protection: 1; mode=blockHello user使用Okta添加身份驗證
在上一教程中 ,我向您展示了如何使用Spring Security OAuth為您的應用程序提供SSO。 您可以在Spring Security 5中執(zhí)行相同的操作,但是您現(xiàn)在還可以指定多個提供程序,而以前是做不到的。 Spring Security 5有一個OAuth 2.0登錄示例 ,以及有關所有工作原理的文檔 。
創(chuàng)建一個OpenID Connect應用
要與Okta集成,您需要在developer.okta.com上注冊一個帳戶 。 確認電子郵件并登錄后,導航至應用程序 > 添加應用程序 。 單擊Web ,然后單擊下一步 。 給應用程序起一個您將記住的名稱,將http://localhost:8080指定為基本URI,并將http://localhost:8080/login/oauth2/code/okta為登錄重定向URI。
將src/main/resources/application.properties重命名為src/main/resources/application.yml ,并使用以下內(nèi)容進行填充。
spring:thymeleaf:cache: falsesecurity:oauth2:client:registration:okta:client-id: {clientId}client-secret: {clientSecret}provider:okta:authorization-uri: https://{yourOktaDomain}.com/oauth2/default/v1/authorizetoken-uri: https://{yourOktaDomain}.com/oauth2/default/v1/tokenuser-info-uri: https://{yourOktaDomain}.com/oauth2/default/v1/userinfojwk-set-uri: https://{yourOktaDomain}.com/oauth2/default/v1/keys將客戶端ID和密碼從OIDC應用程序復制到application.yml文件中。 對于{yourOktaDomain} ,請使用您的域的值(例如dev-158606.oktapreview.com )。 請確保它不包括-admin在里面。
您需要將一些依賴項添加到pom.xml ,Spring Security 5的OAuth配置才能正確初始化。
<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> <dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-springsecurity4</artifactId> </dependency>重新啟動您的應用程序,然后再次導航到http://localhost:8080 。 您會看到一個鏈接,單擊該鏈接可以使用Okta登錄。
注意:如果您想學習如何自定義Spring Security顯示的登錄屏幕,請參閱其OAuth 2.0登錄頁面文檔 。
單擊鏈接后,您應該會看到一個登錄屏幕。
輸入用于創(chuàng)建帳戶的憑據(jù),登錄后,您應該會看到類似以下的屏幕。
注意:可以更改某些內(nèi)容,以便Principal#getName()返回不同的值。 但是, Spring Boot 2.0.0.M7中存在一個錯誤 ,阻止了配置屬性的工作。
使用OIDC獲取用戶信息
更改您的MainController.java使其具有以下代碼。 這段代碼添加了一個/userinfo映射,該映射使用Spring WebFlux的WebClient從用戶信息端點獲取用戶信息。 我從Spring Security 5的OAuth 2.0登錄示例復制了以下代碼。
/* * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.okta.developer.oidc;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.reactive.function.client.ClientRequest; import org.springframework.web.reactive.function.client.ExchangeFilterFunction; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono;import java.util.Collections; import java.util.Map;/** * @author Joe Grandja */ @Controller public class MainController {private final OAuth2AuthorizedClientService authorizedClientService;public MainController(OAuth2AuthorizedClientService authorizedClientService) {this.authorizedClientService = authorizedClientService;}@RequestMapping("/")public String index(Model model, OAuth2AuthenticationToken authentication) {OAuth2AuthorizedClient authorizedClient = this.getAuthorizedClient(authentication);model.addAttribute("userName", authentication.getName());model.addAttribute("clientName", authorizedClient.getClientRegistration().getClientName());return "index";}@RequestMapping("/userinfo")public String userinfo(Model model, OAuth2AuthenticationToken authentication) {OAuth2AuthorizedClient authorizedClient = this.getAuthorizedClient(authentication);Map userAttributes = Collections.emptyMap();String userInfoEndpointUri = authorizedClient.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUri();if (!StringUtils.isEmpty(userInfoEndpointUri)) { // userInfoEndpointUri is optional for OIDC ClientsuserAttributes = WebClient.builder().filter(oauth2Credentials(authorizedClient)).build().get().uri(userInfoEndpointUri).retrieve().bodyToMono(Map.class).block();}model.addAttribute("userAttributes", userAttributes);return "userinfo";}private OAuth2AuthorizedClient getAuthorizedClient(OAuth2AuthenticationToken authentication) {return this.authorizedClientService.loadAuthorizedClient(authentication.getAuthorizedClientRegistrationId(), authentication.getName());}private ExchangeFilterFunction oauth2Credentials(OAuth2AuthorizedClient authorizedClient) {return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {ClientRequest authorizedRequest = ClientRequest.from(clientRequest).header(HttpHeaders.AUTHORIZATION,"Bearer " + authorizedClient.getAccessToken().getTokenValue()).build();return Mono.just(authorizedRequest);});} }在src/main/resources/templates/index.html創(chuàng)建Thymeleaf索引頁面。 您可以使用Thymeleaf對Spring Security的支持,根據(jù)用戶的身份驗證狀態(tài)顯示/隱藏頁面的不同部分。
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"> <head><title>Spring Security - OAuth 2.0 Login</title><meta charset="utf-8" /> </head> <body> <div style="float: right" th:fragment="logout" sec:authorize="isAuthenticated()"><div style="float:left"><span style="font-weight:bold">User: </span><span sec:authentication="name"></span></div><div style="float:none">?</div><div style="float:right"><form action="#" th:action="@{/logout}" method="post"><input type="submit" value="Logout" /></form></div> </div> <h1>OAuth 2.0 Login with Spring Security</h1> <div>You are successfully logged in <span style="font-weight:bold" th:text="${userName}"></span>via the OAuth 2.0 Client <span style="font-weight:bold" th:text="${clientName}"></span> </div> <div>?</div> <div><a href="/userinfo" th:href="@{/userinfo}">Display User Info</a> </div> </body> </html>在src/main/resources/userinfo.html上創(chuàng)建另一個模板以顯示用戶的屬性。
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head><title>Spring Security - OAuth 2.0 User Info</title><meta charset="utf-8" /> </head> <body> <div th:replace="index::logout"></div> <h1>OAuth 2.0 User Info</h1> <div><span style="font-weight:bold">User Attributes:</span><ul><li th:each="userAttribute : ${userAttributes}"><span style="font-weight:bold" th:text="${userAttribute.key}"></span>: <span th:text="${userAttribute.value}"></span></li></ul> </div> </body> </html>現(xiàn)在,當您登錄時,您將看到一個顯示用戶信息的鏈接。
單擊鏈接,您將看到從用戶信息端點檢索到的ID令牌的內(nèi)容。
了解有關Spring Security和OIDC的更多信息
本文向您展示了如何使用OAuth 2.0和Spring Security 5實現(xiàn)登錄。我還向您展示了如何使用OIDC檢索用戶信息。 本文開發(fā)的應用程序的源代碼可以在GitHub上找到 。
這些資源提供了有關Okta和OIDC的其他信息:
- Okta開發(fā)人員文檔及其OpenID Connect API
- 身份,聲明和令牌– OpenID Connect入門,第1部分,共3部分
- 行動中的OIDC – OpenID Connect入門,第2部分,共3部分
- 令牌中有什么? – OpenID Connect入門,第3部分,共3部分
- 使用Spring Security和Thymeleaf向您的應用程序添加基于角色的訪問控制
如果您對此帖子有任何疑問,請在下面發(fā)表評論。 您還可以使用okta標簽將其發(fā)布到Stack Overflow或使用我們的開發(fā)人員論壇 。
在Twitter上關注@OktaDev,以獲取更多精彩內(nèi)容!
“我喜歡編寫身份驗證和授權代碼。” ?從來沒有Java開發(fā)人員。 厭倦了一次又一次地建立相同的登錄屏幕? 嘗試使用Okta API進行托管身份驗證,授權和多因素身份驗證。
Spring Security 5.0和OIDC入門最初于2017年12月18日發(fā)布在Okta開發(fā)人員博客上。
翻譯自: https://www.javacodegeeks.com/2018/03/build-authentication-easy-way-spring-security-5-0-oidc.html
oidc auth2.0
總結
以上是生活随笔為你收集整理的oidc auth2.0_使用Spring Security 5.0和OIDC轻松构建身份验证的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 金字旁一个本 金字旁一个本是什么字
- 下一篇: 人流如织的意思 人流如织的含义