個人 OAuth2 全部文章
- Spring Security 與 OAuth2(介紹):http://www.lxweimin.com/p/68f22f9a00ee
- Spring Security 與 OAuth2(授權(quán)服務(wù)器):http://www.lxweimin.com/p/227f7e7503cb
- Spring Security 與 OAuth2(資源服務(wù)器):http://www.lxweimin.com/p/6dd03375224d
- Spring Security 與 OAuth2(客戶端):http://www.lxweimin.com/p/03e515c2b43f
- Spring Security 與 OAuth2(相關(guān)類參考):http://www.lxweimin.com/p/c2395772bc86
- Spring Security 與 OAuth2(完整案例):http://www.lxweimin.com/p/d80061e6d900
resource-server(資源服務(wù)器)
資源服務(wù)器
- 要訪問資源服務(wù)器受保護的資源需要攜帶令牌(從授權(quán)服務(wù)器獲得)
- 客戶端往往同時也是一個資源服務(wù)器,各個服務(wù)之間的通信(訪問需要權(quán)限的資源)時需攜帶訪問令牌
- 資源服務(wù)器通過 @EnableResourceServer 注解來開啟一個 OAuth2AuthenticationProcessingFilter 類型的過濾器
- 通過繼承 ResourceServerConfigurerAdapter 類來配置資源服務(wù)器
ResourceServerProperties
- OAuth2 為資源服務(wù)器配置提供了 ResourceServerProperties 類,該類會讀取配置文件中對資源服務(wù)器得配置信息(如授權(quán)服務(wù)器公鑰訪問地址)
ResourceServerSecurityConfigurer 可配置屬性
- tokenServices:ResourceServerTokenServices 類的實例,用來實現(xiàn)令牌業(yè)務(wù)邏輯服務(wù)
- resourceId:這個資源服務(wù)的ID,這個屬性是可選的,但是推薦設(shè)置并在授權(quán)服務(wù)中進行驗證
- tokenExtractor 令牌提取器用來提取請求中的令牌
- 請求匹配器,用來設(shè)置需要進行保護的資源路徑,默認的情況下是受保護資源服務(wù)的全部路徑
- 受保護資源的訪問規(guī)則,默認的規(guī)則是簡單的身份驗證(plain authenticated)
- 其他的自定義權(quán)限保護規(guī)則通過 HttpSecurity 來進行配置
解析令牌方法:
- 使用 DefaultTokenServices 在資源服務(wù)器本地配置令牌存儲、解碼、解析方式
- 使用 RemoteTokenServices 資源服務(wù)器通過 HTTP 請求來解碼令牌,每次都請求授權(quán)服務(wù)器端點 /oauth/check_token
- 若授權(quán)服務(wù)器是 JWT 非對稱加密,則需要請求授權(quán)服務(wù)器的 /oauth/token_key 來獲取公鑰 key 進行解碼
代碼案例
令牌解析(JWT 對稱加密)
資源服務(wù)器和授權(quán)服務(wù)器不在同一個應(yīng)用,則需告訴資源服務(wù)器令牌如何存儲與解析,并與授權(quán)服務(wù)器使用相同的密鑰進行解密
@Configuration
@EnableResourceServer
public class OAuth2ResourceConfig extends ResourceServerConfigurerAdapter{
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
//與授權(quán)服務(wù)器使用共同的密鑰進行解析
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("123");
return converter;
}
}
令牌解析(JWT 非對稱加密)
- 非對稱加密需要公鑰,可以從本地獲取,也可以從授權(quán)服務(wù)器提供的公鑰端點獲取
- 若本地獲取不到公鑰資源文件 pubkey.txt 則從授權(quán)服務(wù)器端點獲取
@Configuration
@EnableResourceServer
public class OAuth2ResourceConfig extends ResourceServerConfigurerAdapter {
@Autowired
private ResourceServerProperties resourceServerProperties;
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
//設(shè)置用于解碼的非對稱加密的公鑰
converter.setVerifierKey(getPubKey());
return converter;
}
private String getPubKey() {
Resource resource = new ClassPathResource("pubkey.txt");
try (BufferedReader br = new BufferedReader(new InputStreamReader(resource.getInputStream()))) {
System.out.println("本地公鑰");
return br.lines().collect(Collectors.joining("\n"));
} catch (IOException ioe) {
return getKeyFromAuthorizationServer();
}
}
private String getKeyFromAuthorizationServer() {
ObjectMapper objectMapper = new ObjectMapper();
String pubKey = new RestTemplate().getForObject(resourceServerProperties.getJwt().getKeyUri(), String.class);
try {
Map map = objectMapper.readValue(pubKey, Map.class);
System.out.println("聯(lián)網(wǎng)公鑰");
return map.get("value").toString();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
令牌解析(通過訪問授權(quán)服務(wù)器解析令牌-適用 JDBC、內(nèi)存存儲)
- 資源服務(wù)器通過訪問授權(quán)服務(wù)器 /oauth/check_token 端點解析令牌需要使用 RemoteTokenServices
- 并且使用 DefaultAccessTokenConverter 來實現(xiàn)令牌數(shù)據(jù)的存儲
@Autowired
private OAuth2ClientProperties oAuth2ClientProperties;
@Autowired
private AuthorizationServerProperties authorizationServerProperties;
@Bean
public ResourceServerTokenServices tokenServices() {
RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
remoteTokenServices.setCheckTokenEndpointUrl(authorizationServerProperties.getCheckTokenAccess());
remoteTokenServices.setClientId(oAuth2ClientProperties.getClientId());
remoteTokenServices.setClientSecret(oAuth2ClientProperties.getClientSecret());
remoteTokenServices.setAccessTokenConverter(accessTokenConverter());
return remoteTokenServices;
}
@Bean
public AccessTokenConverter accessTokenConverter() {
return new DefaultAccessTokenConverter();
}
- 修改配置文件
security:
oauth2:
client:
clientId: resource1
clientSecret: secret
userAuthorizationUri: http://localhost:9005/oauth/authorize
grant-type: password
scope: read
access-token-uri: http://localhost:9005/oauth/token
resource:
userInfoUri: http://localhost:9005/user
authorization:
check-token-access: http://localhost:9005/oauth/check_token
basic:
enabled: false