<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    paulwong

    使用Spring Cloud Security OAuth2搭建授權(quán)服務(wù)

    Spring Cloud Security OAuth2 是 Spring 對 OAuth2 的開源實現(xiàn),優(yōu)點是能與Spring Cloud技術(shù)線無縫集成,如果全部使用默認(rèn)配置,開發(fā)者只需要添加注解就能完成 OAuth2 授權(quán)服務(wù)的搭建。

    1. 添加依賴

    授權(quán)服務(wù)是基于Spring Security的,因此需要在項目中引入兩個依賴:

    <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-security</artifactId>
    </dependency>

    <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-oauth2</artifactId>
     </dependency>


    前者為 Security,后者為Security的OAuth2擴展。

    2. 添加注解和配置

    在啟動類中添加@EnableAuthorizationServer注解:

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


    完成這些我們的授權(quán)服務(wù)最基本的骨架就已經(jīng)搭建完成了。但是要想跑通整個流程,我們必須分配 client_idclient_secret才行。Spring Security OAuth2的配置方法是編寫@Configuration類繼承AuthorizationServerConfigurerAdapter,然后重寫void configure(ClientDetailsServiceConfigurer clients)方法,如:

    @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory() // 使用in-memory存儲
                    .withClient("client") // client_id
                    .secret("secret") // client_secret
                    .authorizedGrantTypes("authorization_code") // 該client允許的授權(quán)類型
                    .scopes("app"); // 允許的授權(quán)范圍
        }


    3. 授權(quán)流程

    訪問授權(quán)頁面:

    localhost:8080/oauth/authorize?client_id=client&response_type=code&redirect_uri=http://www.baidu.com


    此時瀏覽器會讓你輸入用戶名密碼,這是因為 Spring Security 在默認(rèn)情況下會對所有URL添加Basic Auth認(rèn)證。默認(rèn)的用戶名為user, 密碼是隨機生成的,在控制臺日志中可以看到。

    oauth2

    畫風(fēng)雖然很簡陋,但是基本功能都具備了。點擊Authorize后,瀏覽器就會重定向到百度,并帶上code參數(shù):

    這里寫圖片描述

    拿到code以后,就可以調(diào)用

    POST/GET http://client:secret@localhost:8080/oauth/token
    • 1

    來換取access_token了:

    curl -X POST -H "Cache-Control: no-cache" -H "Content-Type: application/x-www-form-urlencoded" -d 'grant_type=authorization_code&code=Li4NZo&redirect_uri=http://www.baidu.com' "http://client:secret@localhost:8080/oauth/token"

    返回如下:

    {
      "access_token": "32a1ca28-bc7a-4147-88a1-c95abcc30556",
      "token_type": "bearer",
      "expires_in": 2591999,
      "scope": "app"
    }

    到此我們最最基本的授權(quán)服務(wù)就搭建完成了。然而,這僅僅是個demo,如果要在生產(chǎn)環(huán)境中使用,還需要做更多的工作。

    4. 使用MySQL存儲access_token和client信息

    把授權(quán)服務(wù)器中的數(shù)據(jù)存儲到數(shù)據(jù)庫中并不難,因為 Spring Cloud Security OAuth 已經(jīng)為我們設(shè)計好了一套Schema和對應(yīng)的DAO對象。但在使用之前,我們需要先對相關(guān)的類有一定的了解。

    4.1 相關(guān)接口

    Spring Cloud Security OAuth2通過DefaultTokenServices類來完成token生成、過期等 OAuth2 標(biāo)準(zhǔn)規(guī)定的業(yè)務(wù)邏輯,而DefaultTokenServices又是通過TokenStore接口完成對生成數(shù)據(jù)的持久化。在上面的demo中,TokenStore的默認(rèn)實現(xiàn)為InMemoryTokenStore,即內(nèi)存存儲。 對于Client信息,ClientDetailsService接口負(fù)責(zé)從存儲倉庫中讀取數(shù)據(jù),在上面的demo中默認(rèn)使用的也是InMemoryClientDetialsService實現(xiàn)類。說到這里就能看出,要想使用數(shù)據(jù)庫存儲,只需要提供這些接口的實現(xiàn)類即可。慶幸的是,框架已經(jīng)為我們寫好JDBC實現(xiàn)了,即JdbcTokenStoreJdbcClientDetailsService

    4.2 建表

    要想使用這些JDBC實現(xiàn),首先要建表。框架為我們提前設(shè)計好了schema, 在github上:https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql

    在使用這套表結(jié)構(gòu)之前要注意的是,對于MySQL來說,默認(rèn)建表語句中主鍵是varchar(255)類型,在mysql中執(zhí)行會報錯,原因是mysql對varchar主鍵長度有限制。所以這里改成128即可。其次,語句中會有某些字段為LONGVARBINARY類型,它對應(yīng)mysql的blob類型,也需要修改一下。

    4.3 配置

    數(shù)據(jù)庫建好后,下一步就是配置框架使用JDBC實現(xiàn)。方法還是編寫@Configuration類繼承AuthorizationServerConfigurerAdapter

    @Autowired
        private AuthenticationManager authenticationManager;

        @Autowired
        private DataSource dataSource;
        @Bean // 聲明TokenStore實現(xiàn)
        public TokenStore tokenStore() {
            return new JdbcTokenStore(dataSource);
        }
        @Bean // 聲明 ClientDetails實現(xiàn)
        public ClientDetailsService clientDetails() {
            return new JdbcClientDetailsService(dataSource);
        }
        @Override // 配置框架應(yīng)用上述實現(xiàn)
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints.authenticationManager(authenticationManager);
            endpoints.tokenStore(tokenStore());

            // 配置TokenServices參數(shù)
            DefaultTokenServices tokenServices = new DefaultTokenServices();
            tokenServices.setTokenStore(endpoints.getTokenStore());
            tokenServices.setSupportRefreshToken(false);
            tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
            tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
            tokenServices.setAccessTokenValiditySeconds( (int) TimeUnit.DAYS.toSeconds(30)); // 30天
            endpoints.tokenServices(tokenServices);
        }

    完成這些后,框架就會將中間產(chǎn)生的數(shù)據(jù)寫到mysql中了。oauth_client_details是client表,可以直接在該表中添加記錄來添加client: 
    這里寫圖片描述

    4.4 需要注意的地方

    這里不得不說 Spring 設(shè)計有一個奇葩地的方。注意看oauth_access_token表是存放訪問令牌的,但是并沒有直接在字段中存放token。Spring 使用OAuth2AccessToken來抽象與令牌有關(guān)的所有屬性,在寫入到數(shù)據(jù)庫時,Spring將該對象通過JDK自帶的序列化機制序列成字節(jié)直接保存到了該表的token字段中。也就是說,如果只看數(shù)據(jù)表你是看不出access_token的值是多少,過期時間等信息的。這就給資源服務(wù)器的實現(xiàn)帶來了麻煩。我們的資源提供方并沒有使用Spring Security,也不想引入 Spring Security 的任何依賴,這時候就只能將 DefaultOAuth2AccessToken的源碼copy到資源提供方的項目中,然后讀取token字段并反序列化還原對象來獲取token信息。但是如果這樣做還會遇到反序列化兼容性的問題,具體解決方法參考我另一篇博文:http://blog.csdn.net/neosmith/article/details/52539614

    5. 總結(jié)

    至此一個能在生產(chǎn)環(huán)境下使用的授權(quán)服務(wù)就搭建好了。其實我們在實際使用時應(yīng)該適當(dāng)定制JdbcTokenStoreClientDetailsService來實適應(yīng)業(yè)務(wù)需要,甚至可以直接從0開始實現(xiàn)接口,完全不用框架提供的實現(xiàn)。另外,Spring 直接將DefaultOAuth2AccessToken序列化成字節(jié)保存到數(shù)據(jù)庫中的設(shè)計,我認(rèn)為是非常不合理的。或許設(shè)計者的初衷是保密access_token,但是通過加密的方法也可以實現(xiàn),完全不應(yīng)該直接扔字節(jié)。不過通過定制TokenStore接口,我們可以使用自己的表結(jié)構(gòu)而不拘泥于默認(rèn)實現(xiàn)。

    http://blog.csdn.net/tracker_w/article/category/6360121

    http://blog.csdn.net/neosmith/article/details/52539927

    posted on 2016-09-16 18:22 paulwong 閱讀(8749) 評論(0)  編輯  收藏 所屬分類: MICROSERVICESPRING CLOUD

    主站蜘蛛池模板: 亚洲综合久久久久久中文字幕| 亚洲日本国产综合高清| 2020亚洲男人天堂精品| 美女黄色免费网站| 久久午夜羞羞影院免费观看| 日本大片在线看黄a∨免费| 亚洲AV无码专区亚洲AV伊甸园| 亚洲精品久久无码| 久久99精品免费视频| 男女啪啪永久免费观看网站| 久久精品国产亚洲AV麻豆王友容 | 免费无码又爽又刺激聊天APP| 亚洲午夜无码片在线观看影院猛| 亚洲人成在线播放| 中文字幕在线观看免费| 天天看片天天爽_免费播放| 久久夜色精品国产亚洲AV动态图 | 日日狠狠久久偷偷色综合免费 | 久久伊人亚洲AV无码网站| 亚洲首页国产精品丝袜| 国产午夜无码精品免费看| 国产成人免费全部网站| 亚洲日本视频在线观看| 久青草视频在线观看免费| 四虎成人免费网址在线| 亚洲视频日韩视频| 男女一边摸一边做爽的免费视频| 在线不卡免费视频| 亚洲妇女水蜜桃av网网站| 爽爽爽爽爽爽爽成人免费观看 | 哒哒哒免费视频观看在线www | 99精品全国免费观看视频| 亚洲av无码av制服另类专区| 瑟瑟网站免费网站入口| 性生交片免费无码看人| 久久久久亚洲AV无码永不| 国产在线精品观看免费观看| 又粗又硬又黄又爽的免费视频| 亚洲欧洲日韩极速播放| 亚洲免费二区三区| 亚洲成人中文字幕|