日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

前言

微服務架構下統?認證思路主要有兩種形式:

1、基于 Session 的認證?式在分布式的環境下,基于 session 的認證會出現?個問題,每個應?服務都需要在session中存儲?戶身份信息,通過負載均衡將本地的請求分配到另?個應?服務需要將 session 信息帶過去,否則會重新認證。我們可以使? Session 共享、Session 黏貼等?案。Session ?案也有缺點,?如基于 cookie ,移動端不能有效使?等

2、基于 token 的認證?式?;趖oken的認證?式,服務端不?存儲認證數據,易維護擴展性強, 客戶端可以把token 存在任意地?,并且可以實現 web 和 App 統?認證機制。其缺點也很明顯,token 由于?包含信息,因此?般數據量較?,?且每次請求 都需要傳遞,因此?較占帶寬。另外,token 的簽名驗簽操作也會給 cpu 帶來額外的處理負擔。

下面我們就基于 token 的認證?式。采用 OAuth2 框架來實現。

OAuth2 開放授權協議/標準

OAuth(開放授權)是?個開放協議/標準,允許?戶授權第三?應?訪問他們存儲在另外的服務提供者上的信息,?不需要將?戶名和密碼提供給第三?應?或分享他們數據的所有內容。允許?戶授權第三?應?訪問他們存儲在另外的服務提供者上的信息,?不需要將?戶名和密碼提供給第三?應?或分享他們數據的所有內容。

OAuth2 協議流程圖如下:

OAuth2+JWT 實現權限驗證

 

1、客戶端請求用戶授權

2、用戶確認授權

3、客戶端收到授權許可后,向認證服務器申請令牌

4、認證服務器驗證授權許可,向客戶端返回有效令牌

5、客戶端攜帶有效令牌訪問資源服務器

6、資源服務器從認證服務器中驗證有效令牌。

7、驗證通過后,返回對應的資源給客戶端。

什么情況下需要使? OAuth2 ?

第三?授權登錄的場景:?如,我們經常登錄?些?站或者應?的時候,可以選擇使?第三?授權登錄的?式,?如:微信授權登錄、QQ授權登錄、微博授權登錄等,這是典型的 OAuth2 使?場景。單點登錄的場景:如果項?中有很多微服務或者公司內部有很多服務,可以專?做?個認證中?(充當認證平臺??),所有的服務都要到這個認證中?做認證,只做?次登錄,就可以在多個授權范圍內的服務中?由串?。

Spring Cloud OAuth2 + JWT 實現

Spring Cloud OAuth2 是 Spring Cloud 體系對OAuth2協議的實現,可以?來做多個微服務的統?認證(驗證身份合法性)授權(驗證權限)。通過向OAuth2服務(統?認證授權服務)發送某個類型的 grant_type 進?集中認證和授權,從?獲得 access_token(訪問令牌),?這個 token 是受其他微服務信任的。

使? OAuth2 解決問題的本質是,引?了?個認證授權層,認證授權層連接了資源的擁有者,在授權層??,資源的擁有者可以給第三?應?授權去訪問我們的某些受保護資源。

搭建認證服務器

創建一個新的的模塊,service-oauth-hw-9900。

依賴

pom 文件中依賴如下:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security.oauth.boot</groupId>
    <artifactId>spring-security-oauth2-autoconfigure</artifactId>
    <version>2.1.11.RELEASE</version>
</dependency>
<!--引入security對oauth2的支持-->
<dependency>
    <groupId>org.springframework.security.oauth</groupId>
    <artifactId>spring-security-oauth2</artifactId>
    <version>2.3.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

配置文件

server:
  port: 9900
spring:
  application:
    name: service-oauth-hw
  zipkin:
    base-url: http://127.0.0.1:8771 # zipkin server的請求地址
    sender:
      # web 客戶端將蹤跡日志數據通過網絡請求的方式傳送到服務端,另外還有配置
      # kafka/rabbit 客戶端將蹤跡日志數據傳遞到mq進行中轉
      type: web
    sleuth:
      sampler:
        # 采樣率 1 代表100%全部采集 ,默認0.1 代表10% 的請求蹤跡數據會被采集
        # 生產環境下,請求量非常大,沒有必要所有請求的蹤跡數據都采集分析,對于網絡包括server端壓力都是比較大的,可以配置采樣率采集一定比例的請求的蹤跡數據進行分析即可
        probability: 1
eureka:
  client:
    serviceUrl: # eureka server的路徑
      defaultZone: http://quellanan.a:8761/eureka/,http://quellanan.b:8762/eureka/ #把 eureka 集群中的所有 url 都填寫了進來,也可以只寫一臺,因為各個 eureka server 可以同步注冊表
    instance:
      prefer-ip-address: true #使用ip注冊
#分布式鏈路追蹤
logging:
  level:
    org.springframework.web.servlet.DispatcherServlet: debug
    org.springframework.cloud.sleuth: debug

啟動類

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

config

自定義一個 OauthServerConfiger。當前類為Oauth2 server的配置類(需要繼承特定的父類
AuthorizationServerConfigurerAdapter)

@Configuration
@EnableAuthorizationServer  //開啟認證服務器功能
public class OauthServerConfiger extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private AuthenticationManager authenticationManager;
    /**
     * 客戶端詳情配置,
     *  比如client_id,secret
     *  當前這個服務就如同QQ平臺,拉勾網作為客戶端需要qq平臺進行登錄授權認證等,提前需要到QQ平臺注冊,QQ平臺會給拉勾網
     *  頒發client_id等必要參數,表明客戶端是誰
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        super.configure(clients);
        // 客戶端信息存儲在什么地方,可以在內存中,可以在數據庫里
        clients.inMemory()
                // 添加一個client配置,指定其client_id
                .withClient("quellanan")
                //指定客戶端的密碼/安全碼
                .secret("abcdefg")
                //指定客戶端所能訪問資源id清單,此處的資源id是需要在具體的資源服務器上也配置一樣
                .redirectUris("*")
                //認證類型/令牌頒發模式,可以配置多個在這里,但是不一定都用,具體使用哪種方式頒發token,需要客戶端調用的時候傳遞參數指定
                .authorizedGrantTypes("password","refresh_token")
                //客戶端的權限范圍,此處配置為all全部即可
                .scopes("all");
    }
    /**
     * 認證服務器最終是以api接口的方式對外提供服務(校驗合法性并生成令牌、校驗令牌等)
     * 那么,以api接口方式對外的話,就涉及到接口的訪問權限,我們需要在這里進行必要的配置
     * @param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        super.configure(security);
        // 相當于打開endpoints 訪問接口的開關,這樣的話后期我們能夠訪問該接口
        security
                // 允許客戶端表單認證
                .allowFormAuthenticationForClients()
                // 開啟端口/oauth/token_key的訪問權限(允許)
                .tokenKeyAccess("permitAll()")
                // 開啟端口/oauth/check_token的訪問權限(允許)
                .checkTokenAccess("permitAll()");
    }
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        super.configure(endpoints);
        endpoints
                // 指定token的存儲方法
                .tokenStore(tokenStore())
                // token服務的一個描述,可以認為是token生成細節的描述,比如有效時間多少等
                .tokenServices(authorizationServerTokenServices())
                // 指定認證管理器,隨后注入一個到當前類使用即可
                .authenticationManager(authenticationManager)
                .allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST);
    }
    /*
        該方法用于創建tokenStore對象(令牌存儲對象)
        token以什么形式存儲
     */
    public TokenStore tokenStore(){
        return new InMemoryTokenStore();
        // 使用jwt令牌
        //return new JwtTokenStore(jwtAccessTokenConverter());
    }
    /**
     * 該方法用戶獲取一個token服務對象(該對象描述了token有效期等信息)
     */
    public AuthorizationServerTokenServices authorizationServerTokenServices() {
        // 使用默認實現
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setSupportRefreshToken(true); // 是否開啟令牌刷新
        defaultTokenServices.setTokenStore(tokenStore());
        // 針對jwt令牌的添加
        //defaultTokenServices.setTokenEnhancer(jwtAccessTokenConverter());
        // 設置令牌有效時間(一般設置為2個小時)
        defaultTokenServices.setAccessTokenValiditySeconds(20); // access_token就是我們請求資源需要攜帶的令牌
        // 設置刷新令牌的有效時間
        defaultTokenServices.setRefreshTokenValiditySeconds(259200); // 3天
        return defaultTokenServices;
    }
}

關于三個 configure ?法

configure(
ClientDetailsServiceConfifigurer clients):?來配置客戶端詳情服務(ClientDetailsService),客戶端詳情信息在 這?進?初始化,你能夠把客戶端詳情信息寫死在這?或者是通過數據庫來存儲調取詳情信息

confifigure(
AuthorizationServerEndpointsConfifigurer endpoints):?來配置令牌(token)的訪問端點和令牌服務(token services)

confifigure(
AuthorizationServerSecurityConfifigurer oauthServer):?來配置令牌端點的安全約束.

關于 TokenStore

InMemoryTokenStore默認采?,它可以完美的?作在單服務器上(即訪問并發量 壓?不?的情況下,并且它在失敗的時候不會進?備份),?多數的項?都可以使?這個版本的實現來進? 嘗試,你可以在開發的時候使?它來進?管理,因為不會被保存到磁盤中,所以更易于調試。

JdbcTokenStore這是?個基于JDBC的實現版本,令牌會被保存進關系型數據庫。使?這個版本的實現時, 你可以在不同的服務器之間共享令牌信息,使?這個版本的時候請注意把"springjdbc"這個依賴加?到你的 classpath當中。JwtTokenStore 這個版本的全稱是 JSON Web Token(JWT),它可以把令牌相關的數據進?編碼(因此對于后端服務來說,它不需要進?存儲,這將是?個重?優勢),缺點就是這個令牌占?的空間會?較?,如果你加?了?較多?戶憑證信息,JwtTokenStore 不會保存任何數據。

然后再自定義有一個配置類,主要處理用戶名和密碼的校驗等事宜。

@Configuration
public class SecurityConfiger extends WebSecurityConfigurerAdapter {
    @Autowired
    private PasswordEncoder passwordEncoder;
    //@Autowired
    //private JdbcUserDetailsService jdbcUserDetailsService;
    /**
     * 注冊一個認證管理器對象到容器
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
    /**
     * 密碼編碼對象(密碼不進行加密處理)
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }
    /**
     * 處理用戶名和密碼驗證事宜
     * 1)客戶端傳遞username和password參數到認證服務器
     * 2)一般來說,username和password會存儲在數據庫中的用戶表中
     * 3)根據用戶表中數據,驗證當前傳遞過來的用戶信息的合法性
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 在這個方法中就可以去關聯數據庫了,當前我們先把用戶信息配置在內存中
        // 實例化一個用戶對象(相當于數據表中的一條用戶記錄)
        UserDetails user = new User("admin","123456",new ArrayList<>());
        auth.inMemoryAuthentication()
                .withUser(user).passwordEncoder(passwordEncoder);
        //auth.userDetailsService(jdbcUserDetailsService).passwordEncoder(passwordEncoder);
    }
}

JWT 改造統?認證授權中?的令牌存儲機制

JWT 令牌介紹

通過上邊的測試我們發現,當資源服務和授權服務不在?起時資源服務使?RemoteTokenServices 遠程請求授權 服務驗證token,如果訪問量較?將會影響系統的性能。

解決上邊問題: 令牌采?JWT格式即可解決上邊的問題,?戶認證通過會得到?個JWT令牌,JWT令牌中已經包括了?戶相關的信 息,客戶端只需要攜帶JWT訪問資源服務,資源服務根據事先約定的算法??完成令牌校驗,?需每次都請求認證 服務完成授權。

什么是JWT?

JSON Web Token(JWT)是?個開放的?業標準(RFC 7519),它定義了?種簡介的、?包含的協議格式,?于 在通信雙?傳遞json對象,傳遞的信息經過數字簽名可以被驗證和信任。JWT可以使?Hmac算法或使?RSA的公 鑰/私鑰對來簽名,防?被篡改。

JWT令牌結構

JWT 令牌由三部分組成,每部分中間使?點(.)分隔,?如:xxxxx.yyyyy.zzzzz

Header。頭部包括令牌的類型(即JWT)及使?的哈希算法(如HMAC SHA256或RSA),例如

{
 "alg": "HS256",
 "typ": "JWT"
}

將上邊的內容使?Base64Url編碼,得到?個字符串就是JWT令牌的第?部分。

Payload。第?部分是負載,內容也是?個json對象,它是存放有效信息的地?,它可以存放jwt提供的現成字段,? 如:iss(簽發者),exp(過期時間戳), sub(?向的?戶)等,也可?定義字段。 此部分不建議存放敏感信息,因為此部分可以解碼還原原始內容。 最后將第?部分負載使?Base64Url編碼,得到?個字符串就是JWT令牌的第?部分。 ?個例?:

{
 "sub": "1234567890",
 "name": "John Doe",
 "iat": 1516239022
}

Signature。第三部分是簽名,此部分?于防?jwt內容被篡改。 這個部分使?base64url將前兩部分進?編碼,編碼后使?點(.)連接組成字符串,最后使?header中聲明 簽名算法進?簽名。

HMACSHA256(
 base64UrlEncode(header) + "." +
 base64UrlEncode(payload),
 secret)
  1. base64UrlEncode(header):jwt令牌的第?部分。
  2. base64UrlEncode(payload):jwt令牌的第?部分。

secret:簽名所使?的密鑰。

認證服務器端JWT改造(改造主配置類)

/*
該方法用于創建tokenStore對象(令牌存儲對象)
token以什么形式存儲
*/
public TokenStore tokenStore(){
    //return new InMemoryTokenStore();
    // 使用jwt令牌
    return new JwtTokenStore(jwtAccessTokenConverter());
}
/**
* 返回jwt令牌轉換器(幫助我們生成jwt令牌的)
* 在這里,我們可以把簽名密鑰傳遞進去給轉換器對象
* @return
*/
public JwtAccessTokenConverter jwtAccessTokenConverter() {
    JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
    jwtAccessTokenConverter.setSigningKey(sign_key);  // 簽名密鑰
    jwtAccessTokenConverter.setVerifier(new MacSigner(sign_key));  // 驗證時使用的密鑰,和簽名密鑰保持一致
    jwtAccessTokenConverter.setAccessTokenConverter(lagouAccessTokenConvertor);
return jwtAccessTokenConverter;
}

修改 JWT 令牌服務?法

/**
 * 該方法用戶獲取一個token服務對象(該對象描述了token有效期等信息)
 */
public AuthorizationServerTokenServices authorizationServerTokenServices() {
    // 使用默認實現
    DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
    defaultTokenServices.setSupportRefreshToken(true); // 是否開啟令牌刷新
    defaultTokenServices.setTokenStore(tokenStore());
    // 針對jwt令牌的添加
    defaultTokenServices.setTokenEnhancer(jwtAccessTokenConverter());
    // 設置令牌有效時間(一般設置為2個小時)
    defaultTokenServices.setAccessTokenValiditySeconds(20); // access_token就是我們請求資源需要攜帶的令牌
    // 設置刷新令牌的有效時間
    defaultTokenServices.setRefreshTokenValiditySeconds(259200); // 3天
    return defaultTokenServices;
}

總結

我們在實際工作中,token 鑒權的方式是很常見的現在,這一套解決方案也可以直接使用到項目中,小伙伴們趕緊學習起來吧。

分享到:
標簽:OAuth2
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定