1、OAuth2協議中的角色流程概要介紹
OAuth2協議主要使用來認證和授權的,我們先來看一下OAuth2協議中的角色
1.1、用戶:真正的人,大家都有可能是某一個服務的用戶。
1.2、客戶端應用:Web或手機App,直接跟用戶打交道的。通過客戶端應用發http請求,訪問服務。
1.3、認證服務器:作用就是認證,驗證用戶身份發出令牌。
1.4、資源服務器:在這里代表各個微服務。一個認證服務器可以對應多個資源服務器。
大概的流程是:用戶直接訪問客戶端應用,客戶端首先要去認證服務器認證,驗證要訪問微服務用戶的真實性,認證服務器確認用戶身份后,會發出一個代表用戶身份的令牌給客戶端應用,客戶端應用就會拿着令牌去訪問資源服務器(我們的微服務),資源服務器會去認證服務器驗證這個令牌是誰。
2、部分角色准備
2.1、用戶,就是我們自己。
2.2、客戶端應用:http請求工具,可以是Restlet Client、Postman等。
2.3、資源服務器,我們准備兩個簡單的微服務,一個訂單服務,一個價格服務,訂單服務調用價格服務獲取價格。
2.3.1、訂單服務,端口9080
2.3.2、價格服務,端口9070
3.2、pom.xml導入spring-cloud-starter-oauth2依賴
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.2.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Greenwich.SR2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <properties> <java.version>1.8</java.version> <maven.compiler.source>${java.version}</maven.compiler.source> <maven.compiler.target>${java.version}</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> </dependency> </dependencies>
3.3、OAuth2AuthServerConfig,認證服務器配置
/** * OAuth2認證服務器配置類 * 需要繼承AuthorizationServerConfigurerAdapter類,覆蓋里面三個configure方法 * 並添加@EnableAuthorizationServer注解,指定當前應用做為認證服務器 * * @author caofanqi * @date 2020/1/31 18:04 */ @Configuration @EnableAuthorizationServer public class OAuth2AuthServerConfig extends AuthorizationServerConfigurerAdapter { @Resource private AuthenticationManager authenticationManager; /** * 配置授權服務器的安全性 * checkTokenAccess:驗證令牌需要什么條件,isAuthenticated():需要經過身份認證。 * 此處的passwordEncoders是為client secrets配置的。 */ @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security.checkTokenAccess("isAuthenticated()").passwordEncoder(new BCryptPasswordEncoder()); } /** * 配置客戶端服務 */ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients //配置在內存中 .inMemory() //客戶端應用的用戶名 .withClient("webApp") //客戶端應用加密過的密碼 .secret(new BCryptPasswordEncoder().encode("123456")) //orderApp可以獲取所有的權限集合,用於做ACL的權限控制 .scopes("read", "write") //發出去令牌的有效期,單位秒 .accessTokenValiditySeconds(3600) //可以訪問哪些資源服務器 .resourceIds("order-server") //授權的方式 .authorizedGrantTypes("password") .and() //訂單服務要訪問資源服務器驗證令牌,所以也需要配置相關信息 .withClient("orderService") .secret(new BCryptPasswordEncoder().encode("123456")) .scopes("read", "write") .accessTokenValiditySeconds(3600) .resourceIds("order-server") .authorizedGrantTypes("password"); } /** * 配置授權服務器終端的非安全特征 * authenticationManager 校驗用戶信息是否合法 */ @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager); } }
3.4、WebSecurityConfig,安全配置
/** * WebSecurity安全配置 * * @author caofanqi * @date 2020/1/31 22:48 */ @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Resource private UserDetailsService userDetailsService; @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } /** * AuthenticationManagerBuilder可以幫助我們構建出一個AuthenticationManager,需要UserDetailsService和PasswordEncoder */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } /** * 將AuthenticationManager暴露成Bean */ @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } }
3.5、UserDetailsService
/** * 查詢用戶信息 * @author caofanqi * @date 2020/2/1 3:41 */ @Component public class UserDetailsServiceImpl implements UserDetailsService { /** * 此處為了簡便,沒有連接數據庫,不管什么用戶名,只要密碼是123456就會通過驗證 */ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return User.withUsername(username) .password(new BCryptPasswordEncoder().encode("123456")) .authorities("ROLE_ADMIN").build(); } }
3.6、啟動項目,端口9020,看控制台有三個路徑,/oauth/token獲取token,/oauth/token_key,/oauth/check_token用於校驗token
3.7、測試密碼模式獲取令牌
3.7.1、請求路徑:http://127.0.0.1:9020/oauth/token
3.7.2、使用httpBasic添加客戶端認證信息
3.7.3、表單添加用戶信息,username(用戶名)、password(密碼)、grant_type(授權模式)、scope(權限范圍)
3.7.4、返回值,access_token(令牌)、token_type(令牌類型)、expires_in(有效期剩余時間)、scope(權限范圍)。
項目源碼:https://github.com/caofanqi/study-security/tree/dev-AuthorizationServer