溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

java中怎么構(gòu)建一個(gè)OAuth2授權(quán)服務(wù)器

發(fā)布時(shí)間:2021-07-13 10:24:39 來(lái)源:億速云 閱讀:297 作者:Leah 欄目:開(kāi)發(fā)技術(shù)

今天就跟大家聊聊有關(guān)java中怎么構(gòu)建一個(gè)OAuth2授權(quán)服務(wù)器,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

構(gòu)建 OAuth3 授權(quán)服務(wù)器

從表現(xiàn)形式上看,OAuth3 授權(quán)服務(wù)器也是一個(gè)獨(dú)立的微服務(wù),因此構(gòu)建授權(quán)服務(wù)器的方法也是創(chuàng)建一個(gè) SpringBoot 應(yīng)用程序,我們需要引入對(duì)應(yīng)的 Maven 依賴,如下所示:

<dependency>
    <groupId>org.springframework.security.oauth</groupId>
    <artifactId>spring-security-oauth3</artifactId>
</dependency>

這里的 spring-security-oauth3 就是來(lái)自 Spring Security 中的 OAuth3 庫(kù)?,F(xiàn)在 Maven 依賴已經(jīng)添加完畢,下一步就是構(gòu)建 Bootstrap 類作為訪問(wèn)的入口:

@SpringBootApplication
@EnableAuthorizationServer
public class AuthServer {
    public static void main(String[] args) {
        SpringApplication.run(AuthServer.class, args);
    }
}

請(qǐng)注意,這里出現(xiàn)了一個(gè)新的注解 @EnableAuthorizationServer,這個(gè)注解的作用在于為微服務(wù)運(yùn)行環(huán)境提供一個(gè)基于 OAuth3 協(xié)議的授權(quán)服務(wù),該授權(quán)服務(wù)會(huì)暴露一系列基于 RESTful 風(fēng)格的端點(diǎn)(例如 /oauth/authorize 和 /oauth/token)供 OAuth3 授權(quán)流程使用。

構(gòu)建 OAuth3 授權(quán)服務(wù)只是集成 OAuth3 協(xié)議的第一步,授權(quán)服務(wù)器是一種集中式系統(tǒng),管理著所有與安全性流程相關(guān)的客戶端和用戶信息。因此,接下來(lái)我們需要在授權(quán)服務(wù)器中對(duì)這些基礎(chǔ)信息進(jìn)行初始化,而 Spring Security 為我們提供了各種配置類來(lái)實(shí)現(xiàn)這一目標(biāo)。

設(shè)置客戶端和用戶認(rèn)證信息

OAuth3.0 有幾個(gè)授權(quán)模式:授權(quán)碼模式、簡(jiǎn)化模式、密碼模式、客戶端憑證模式。其中,密碼模式以其簡(jiǎn)單性得到了廣泛的應(yīng)用。在接下來(lái)的內(nèi)容中,我們就以密碼模式為例展開(kāi)講解。

在密碼模式下,用戶向客戶端提供用戶名和密碼,并將用戶名和密碼發(fā)給授權(quán)服務(wù)器從而請(qǐng)求 Token。授權(quán)服務(wù)器首先會(huì)對(duì)密碼憑證信息進(jìn)行認(rèn)證,確認(rèn)無(wú)誤后,向客戶端發(fā)放 Token。整個(gè)流程如下圖所示:

java中怎么構(gòu)建一個(gè)OAuth2授權(quán)服務(wù)器

請(qǐng)注意,授權(quán)服務(wù)器在這里執(zhí)行認(rèn)證操作的目的是驗(yàn)證傳入的用戶名和密碼是否正確。在密碼模式下,這一步是必需的,如果采用其他授權(quán)模式,不一定會(huì)有用戶認(rèn)證這一環(huán)節(jié)。

確定采用密碼模式后,我們來(lái)看為了實(shí)現(xiàn)這一授權(quán)模式,需要對(duì)授權(quán)服務(wù)器做哪些開(kāi)發(fā)工作。首先我們需要設(shè)置一些基礎(chǔ)數(shù)據(jù),包括客戶端信息和用戶信息。

設(shè)置客戶端信息

我們先來(lái)看如何設(shè)置客戶端信息。設(shè)置客戶端時(shí),用到的配置類是 ClientDetailsServiceConfigurer,該配置類用來(lái)配置客戶端詳情服務(wù) ClientDetailsService。用于描述客戶端詳情的 ClientDetails 接口則包含了與安全性控制相關(guān)的多個(gè)重要方法,該接口中的部分方法定義如下:

public interface ClientDetails extends Serializable {
     //客戶端唯一性 Id
     String getClientId();
     //客戶端安全碼
     String getClientSecret();
     //客戶端的訪問(wèn)范圍
     Set<String> getScope();
     //客戶端可以使用的授權(quán)模式

     Set<String> getAuthorizedGrantTypes();
     …
}

首先 ClientId 是一個(gè)必備屬性,用來(lái)唯一標(biāo)識(shí)客戶的 Id,而 ClientSecret 代表客戶端安全碼。這里的 Scope 用來(lái)限制客戶端的訪問(wèn)范圍,如果這個(gè)屬性為空,客戶端就擁有全部的訪問(wèn)范圍。常見(jiàn)的設(shè)置方式可以是 webclient 或 mobileclient,分別代表 Web 端和移動(dòng)端。

最后,authorizedGrantTypes 代表客戶端可以使用的授權(quán)模式,可選的范圍包括代表授權(quán)碼模式的 authorization_code、代表隱式授權(quán)模式 implicit、代表密碼模式的 password 以及代表客戶端憑據(jù)模式的 client_credentials。這個(gè)屬性在設(shè)置上也可以添加 refresh_token,通過(guò)刷新操作獲取以上授權(quán)模式下產(chǎn)生的新 Token。

和實(shí)現(xiàn)認(rèn)證過(guò)程類似,Spring Security 也提供了 AuthorizationServerConfigurerAdapter 這個(gè)配置適配器類來(lái)簡(jiǎn)化配置類的使用方式。我們可以通過(guò)繼承該類并覆寫(xiě)其中的 configure(ClientDetailsServiceConfigurer clients) 方法進(jìn)行配置。使用 AuthorizationServerConfigurerAdapter 進(jìn)行客戶端信息配置的基本代碼結(jié)構(gòu)如下:

@Configuration

public class SpringAuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients.inMemory()
        .withClient("spring")
        .secret("{noop}spring_secret")
        .authorizedGrantTypes("refresh_token", "password", "client_credentials")
        .scopes("webclient", "mobileclient");
    }
}

可以看到,我們創(chuàng)建了一個(gè) SpringAuthorizationServerConfigurer 類來(lái)繼承 AuthorizationServerConfigurerAdapter,并通過(guò) ClientDetailsServiceConfigurer 配置類設(shè)置了授權(quán)模式為密碼模式。在授權(quán)服務(wù)器中存儲(chǔ)客戶端信息有兩種方式,一種就是如上述代碼所示的基于內(nèi)存級(jí)別的存儲(chǔ),另一種則是通過(guò) JDBC 在數(shù)據(jù)庫(kù)中存儲(chǔ)詳情信息。為了簡(jiǎn)單起見(jiàn),這里使用了內(nèi)存級(jí)別的存儲(chǔ)方式。

同時(shí)我們注意到,在設(shè)置客戶端安全碼時(shí)使用了"{noop}spring_secret"這種格式。這是因?yàn)樵?Spring Security 5 中統(tǒng)一使用 PasswordEncoder 對(duì)密碼進(jìn)行編碼,在設(shè)置密碼時(shí)要求格式為“{id}password”。而這里的前綴“{noop}”就是代表具體 PasswordEncoder 的 id,表示我們使用的是 NoOpPasswordEncoder。

@EnableAuthorizationServer 注解會(huì)暴露一系列的端點(diǎn),而授權(quán)過(guò)程是使用 AuthorizationEndpoint 這個(gè)端點(diǎn)進(jìn)行控制的。要想對(duì)該端點(diǎn)的行為進(jìn)行配置,你可以使用 AuthorizationServerEndpointsConfigurer 這個(gè)配置類。和 ClientDetailsServiceConfigurer 配置類一樣,我們也通過(guò)使用 AuthorizationServerConfigurerAdapter 配置適配器類進(jìn)行配置。

因?yàn)槲覀冎付耸跈?quán)模式為密碼模式,而密碼模式包含認(rèn)證環(huán)節(jié)。所以針對(duì) AuthorizationServerEndpointsConfigurer 配置類需要指定一個(gè)認(rèn)證管理器 AuthenticationManager,用于對(duì)用戶名和密碼進(jìn)行認(rèn)證。同樣因?yàn)槲覀冎付嘶诿艽a的授權(quán)模式,所以需要指定一個(gè)自定義的 UserDetailsService 來(lái)替換全局的實(shí)現(xiàn),可以通過(guò)如下代碼來(lái)配置 AuthorizationServerEndpointsConfigurer:

@Configuration

public class SpringAuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {

 @Autowired
 private AuthenticationManager authenticationManager;

 @Autowired
 private UserDetailsService userDetailsService;

 @Override

 public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {   endpoints.authenticationManager(authenticationManager).userDetailsService(userDetailsService);
 } 
}

至此,客戶端設(shè)置工作全部完成,我們所做的事情就是實(shí)現(xiàn)了一個(gè)自定義的 SpringAuthorizationServerConfigurer 配置類并覆寫(xiě)了對(duì)應(yīng)的配置方法。

設(shè)置用戶認(rèn)證信息

設(shè)置用戶認(rèn)證信息所依賴的配置類是 WebSecurityConfigurer 類,Spring Security 同樣提供了 WebSecurityConfigurerAdapter 類來(lái)簡(jiǎn)化該配置類的使用方式,我們可以繼承 WebSecurityConfigurerAdapter 類并且覆寫(xiě)其中的 configure() 的方法來(lái)完成配置工作。

關(guān)于 WebSecurityConfigurer 配置類,我們首先需要明確配置的內(nèi)容。實(shí)際上,設(shè)置用戶信息非常簡(jiǎn)單,只需要指定用戶名(User)、密碼(Password)和角色(Role)這三項(xiàng)數(shù)據(jù)即可,如下所示:

@Configuration

public class SpringWebSecurityConfigurer extends WebSecurityConfigurerAdapter {

 @Override
 @Bean
 public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
 }

 @Override
 @Bean
 public UserDetailsService userDetailsServiceBean() throws Exception {
            return super.userDetailsServiceBean();
 }

 @Override
 protected void configure(AuthenticationManagerBuilder builder) throws Exception {
 builder
            .inMemoryAuthentication()
            .withUser("user1")
            .password("{noop}password1")
            .roles("USER")
            .and()
            .withUser("admin")
            .password("{noop}password2")
            .roles("USER", "ADMIN");
 }
}

結(jié)合上面的代碼,我們看到構(gòu)建了具有不同角色和密碼的兩個(gè)用戶,請(qǐng)注意"user1"代表的角色是一個(gè)普通用戶,"admin"則具有管理員角色。我們?cè)谠O(shè)置密碼時(shí),同樣需要添加前綴“{noop}”。同時(shí),我們還看到 authenticationManagerBean()和 userDetailsServiceBean() 方法分別返回了父類的默認(rèn)實(shí)現(xiàn),而這里返回的 UserDetailsService 和 AuthenticationManager 在前面設(shè)置客戶端時(shí)會(huì)用到。

生成 Token

現(xiàn)在,OAuth3 授權(quán)服務(wù)器已經(jīng)構(gòu)建完畢,啟動(dòng)這個(gè)授權(quán)服務(wù)器,我們就可以獲取 Token。我們?cè)跇?gòu)建 OAuth3 服務(wù)器時(shí)已經(jīng)提到授權(quán)服務(wù)器中會(huì)暴露一批端點(diǎn)供 HTTP 請(qǐng)求進(jìn)行訪問(wèn),而獲取 Token 的端點(diǎn)就是http://localhost:2000/oauth/token。在使用該端點(diǎn)時(shí),我們需要提供前面配置的客戶端信息和用戶信息。

這里使用 Postman 來(lái)模擬 HTTP 請(qǐng)求,客戶端信息設(shè)置方式如下圖所示:

java中怎么構(gòu)建一個(gè)OAuth2授權(quán)服務(wù)器

我們?cè)凇癆uthorization”請(qǐng)求頭中指定認(rèn)證類型為“Basic Auth”,然后設(shè)置客戶端名稱和客戶端安全碼分別為“spring”和“spring_secret”。

接下來(lái)我們指定針對(duì)授權(quán)模式的專用配置信息。首先是用于指定授權(quán)模式的 grant_type 屬性,以及用于指定客戶端訪問(wèn)范圍的 scope 屬性,這里分別設(shè)置為 “password”和“webclient”。既然設(shè)置了密碼模式,所以也需要指定用戶名和密碼用于識(shí)別用戶身份,這里,我們以“spring_user”這個(gè)用戶為例進(jìn)行設(shè)置,如下圖所示:

java中怎么構(gòu)建一個(gè)OAuth2授權(quán)服務(wù)器

在 Postman 中執(zhí)行這個(gè)請(qǐng)求,會(huì)得到如下所示的返回結(jié)果:

{
    "access_token":"d2066f68-665b-4038-9dbe-5dd1035e75a0",
    "token_type":"bearer",
    "refresh_token":"44009836-731c-4e6a-9cc3-274ce3af8c6b",
    "expires_in":3599,
    "scope":"all"
}

可以看到,除了作為請(qǐng)求參數(shù)的 scope,這個(gè)返回結(jié)果中還包含了 access_token、token_type、refresh_token 和 expires_in 等屬性。這些屬性都很重要。當(dāng)然,因?yàn)槊看握?qǐng)求生成的 Token 都是唯一的,所以你在嘗試時(shí)獲取的結(jié)果可能與我的不同。

看完上述內(nèi)容,你們對(duì)java中怎么構(gòu)建一個(gè)OAuth2授權(quán)服務(wù)器有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI