創(chuàng)建認(rèn)證服務(wù)auth
(1)引入依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.1.1.RELEASE</version>
</dependency>
第一步锋边、創(chuàng)建配置類
自定義配置類OAuth2AuthorizationServer,繼承AuthorizationServerConfigurerAdapter,添加注解
@Configuration
@EnableAuthorizationServer
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter {
}
重寫AuthorizationServerConfigurerAdapter中的三個(gè)方法,配置授權(quán)服務(wù)器
public class AuthorizationServerConfigurerAdapter implements AuthorizationServerConfigurer {
public AuthorizationServerConfigurerAdapter() {
}
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
}
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
}
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
}
}
這三個(gè)方法的作用:
ClientDetailsServiceConfigurer:
配置客戶端信息抹腿,客戶端信息在這里進(jìn)行初始化晕鹊,可以在這里寫死也可以通過(guò)數(shù)據(jù)庫(kù)來(lái)存儲(chǔ)和調(diào)取
AuthorizationServerEndpointsConfigurer:
配置令牌服務(wù)和令牌的訪問(wèn)端點(diǎn)
AuthorizationServerSecurityConfigurer:
配置令牌端點(diǎn)的安全約束
第二步松却、配置客戶端信息
配置客戶端信息的 主要配置項(xiàng):
clientId:客戶端id
secret: 客戶端秘鑰
scope:允許的授權(quán)范圍
authorizedGrantTypes:允許客戶端使用的授權(quán)類型
authorities:客戶端可以使用的權(quán)限
客戶端信息 能夠在應(yīng)用程序運(yùn)行的時(shí)候進(jìn)行更新 可以使用內(nèi)存存儲(chǔ)也可以存儲(chǔ)在關(guān)系型數(shù)據(jù)庫(kù)中
接下來(lái)演示用內(nèi)存的方式存儲(chǔ)客戶端信息,配置如下:
/**
* 配置基于內(nèi)存或JDBC的客戶端信息
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()// 使用內(nèi)存存儲(chǔ)
.withClient("c1")//客戶端id
.secret(new BCryptPasswordEncoder().encode("secret"))//客戶端秘鑰
.resourceIds("res1")//資源列表
/**
* 允許給客戶端授權(quán)的5種授權(quán)類型:
* 1 "authorization_code" 授權(quán)碼模式, 2 "password" 密碼模式, 3 "client_credentials" 客戶端模式
* 4 "implicit" 隱式模式, 5 "refresh_token" 刷新令牌
*/
.authorizedGrantTypes("authorization_code","password","client_credentials","implicit","refresh_token")
.scopes("all")//允許的授權(quán)范圍
.autoApprove(false) //false: 如果是授權(quán)碼模式 跳轉(zhuǎn)到授權(quán)頁(yè)面
.redirectUris("http://www.baidu.com");//加上驗(yàn)證回調(diào)地址
}
3捏题、令牌服務(wù)底層實(shí)現(xiàn)原理
(1)底層源碼分析:
AuthorizationServerTokenServices接口定義了一些操作使得你可以對(duì)令牌進(jìn)行一些必要的管理玻褪;
DefaultTokenServices是AuthorizationServerTokenServices的實(shí)現(xiàn)類,可以使用它來(lái)設(shè)置令牌的格式和令牌的存儲(chǔ)公荧;
默認(rèn)創(chuàng)建一個(gè)令牌時(shí),使用隨機(jī)值進(jìn)行填充同规,除了持久化令牌是委托一個(gè)TokenStore接口來(lái)實(shí)現(xiàn)以外循狰,其他功能都由DefaultTokenServices實(shí)現(xiàn);
TokenStore這個(gè)接口有一個(gè)默認(rèn)的實(shí)現(xiàn)類InMemoryTokenStore券勺,如其命名绪钥,所有的令牌都被保存在了內(nèi)存中。
(2)TokenStore的3個(gè)實(shí)現(xiàn)類簡(jiǎn)介:
InMemoryTokenStore:該實(shí)現(xiàn)類被默認(rèn)采用关炼,這種方式是將令牌保存到內(nèi)存中程腹,可以在開(kāi)發(fā)階段使用它做調(diào)試;
JdbcTokenStore:這是一個(gè)基于JDBC的實(shí)現(xiàn)類儒拂,令牌會(huì)被保存進(jìn)關(guān)系型數(shù)據(jù)庫(kù)寸潦。這種實(shí)現(xiàn)方式可以在不同的服務(wù)器之間共享令牌信息,使用該實(shí)現(xiàn)類要導(dǎo)入spring-jdbc依賴
JwtTokenStore:它可以把令牌相關(guān)的數(shù)據(jù)進(jìn)行編碼社痛,不需要進(jìn)行存儲(chǔ)
4见转、令牌服務(wù)代碼實(shí)現(xiàn)
@Autowired
ClientDetailsService clientDetailsService;
@Autowired
TokenStore tokenStore;
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
@Bean
public AuthorizationServerTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setClientDetailsService(clientDetailsService);
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(tokenStore);
tokenServices.setAccessTokenValiditySeconds(7200); //令牌默認(rèn)有效期2小時(shí)
tokenServices.setRefreshTokenValiditySeconds(259200); //刷新令牌默認(rèn)有效期3天
return tokenServices;
}
5、令牌訪問(wèn)端點(diǎn)配置
(1)配置授權(quán)類型
authenticationManager:
用于密碼授權(quán)模式
authorizationCodeServices:
用于授權(quán)碼模式
implicitGrantService:
用于設(shè)置隱式授權(quán)模式
userDetailsService:
配置自定義的userDetailsService實(shí)現(xiàn)類
tokenGranter:
四種授權(quán)模式不滿足需求的情況下蒜哀,做擴(kuò)展增強(qiáng)
https://www.toobug.cn/post/2865.html
(2)配置授權(quán)端點(diǎn)的URL:
我們可以通過(guò)AuthorizationServerEndpointsConfigurer 對(duì)象的 pathMapping() 方法來(lái)配置端點(diǎn)URL鏈接斩箫,它有兩個(gè)參數(shù):
第一個(gè)參數(shù):String 類型,它是這個(gè)端點(diǎn)URL的默認(rèn)鏈接
第二個(gè)參數(shù):String 類型撵儿,它是你要替換的URL鏈接
框架的默認(rèn)URL鏈接如下:
/oauth/authorize:授權(quán)端點(diǎn)
/oauth/token:令牌端點(diǎn)
/oauth/confirm_access:用戶確認(rèn)授權(quán)提交端點(diǎn)
/oauth/error:授權(quán)服務(wù)錯(cuò)誤信息端點(diǎn)
/oauth/check_token:用于資源服務(wù)訪問(wèn)的令牌解析端點(diǎn)
/oauth/token_key:如果使用的是JWT令牌乘客,則為 提供公有密匙的端點(diǎn)
需要注意的是授權(quán)端點(diǎn)這個(gè)URL應(yīng)該被spring security保護(hù)起來(lái),只供授權(quán)用戶訪問(wèn)
6淀歇、配置令牌端點(diǎn)的安全約束
AuthorizationServerSecurityConfigurer用來(lái)配置令牌端點(diǎn)的安全約束易核,配置如下:
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
//tokenkey端點(diǎn)完全公開(kāi)
.tokenKeyAccess("permitAll()")
//checkToken端點(diǎn)完全公開(kāi)
.checkTokenAccess("permitAll()")
//允許表單認(rèn)證
.allowFormAuthenticationForClients();
}
web安全配置
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 為特定的Http請(qǐng)求配置基于Web的安全約束
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
//關(guān)閉csrf
http.csrf().disable()
//不通過(guò)Session獲取SecurityContext
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
//對(duì)于登錄接口,允許匿名訪問(wèn)
.antMatchers("/user/login").anonymous() //匿名訪問(wèn)(未登錄可訪問(wèn)房匆,登錄后不可訪問(wèn))
.antMatchers("/user/hello").hasAuthority("system:test:index")
.anyRequest().authenticated();
//允許跨域
http.cors();
}
/**
* 實(shí)例化AuthenticationManager對(duì)象耸成,將它注入spring容器
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}