Spring Security 與 OAuth2(資源伺服器)
阿新 • • 發佈:2019-01-08
resource-server(資源伺服器)
資源伺服器
- 要訪問資源伺服器受保護的資源需要攜帶令牌(從授權伺服器獲得)
- 客戶端往往同時也是一個資源伺服器,各個服務之間的通訊(訪問需要許可權的資源)時需攜帶訪問令牌
- 資源伺服器通過 @EnableResourceServer 註解來開啟一個 OAuth2AuthenticationProcessingFilter 型別的過濾器
- 通過繼承 ResourceServerConfigurerAdapter 類來配置資源伺服器
ResourceServerProperties
- OAuth2 為資源伺服器配置提供了 ResourceServerProperties 類,該類會讀取配置檔案中對資源伺服器得配置資訊(如授權伺服器公鑰訪問地址)
ResourceServerSecurityConfigurer 可配置屬性
- tokenServices:ResourceServerTokenServices 類的例項,用來實現令牌業務邏輯服務
- resourceId:這個資源服務的ID,這個屬性是可選的,但是推薦設定並在授權服務中進行驗證
- tokenExtractor 令牌提取器用來提取請求中的令牌
- 請求匹配器,用來設定需要進行保護的資源路徑,預設的情況下是受保護資源服務的全部路徑
- 受保護資源的訪問規則,預設的規則是簡單的身份驗證(plain authenticated)
- 其他的自定義許可權保護規則通過 HttpSecurity 來進行配置
解析令牌方法:
- 使用 DefaultTokenServices 在資源伺服器本地配置令牌儲存、解碼、解析方式
- 使用 RemoteTokenServices 資源伺服器通過 HTTP 請求來解碼令牌,每次都請求授權伺服器端點 /oauth/check_token
- 若授權伺服器是 JWT 非對稱加密,則需要請求授權伺服器的 /oauth/token_key 來獲取公鑰 key 進行解碼
程式碼案例
令牌解析(JWT 對稱加密)
資源伺服器和授權伺服器不在同一個應用,則需告訴資源伺服器令牌如何儲存與解析,並與授權伺服器使用相同的金鑰進行解密
@Configuration @EnableResourceServer public class OAuth2ResourceConfig extends ResourceServerConfigurerAdapter{ @Bean public TokenStore tokenStore() { return new JwtTokenStore(jwtAccessTokenConverter()); } //與授權伺服器使用共同的金鑰進行解析 @Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey("123"); return converter; } }
令牌解析(JWT 非對稱加密)
- 非對稱加密需要公鑰,可以從本地獲取,也可以從授權伺服器提供的公鑰端點獲取
- 若本地獲取不到公鑰資原始檔 pubkey.txt 則從授權伺服器端點獲取
@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();
//設定用於解碼的非對稱加密的公鑰
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("聯網公鑰");
return map.get("value").toString();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
令牌解析(通過訪問授權伺服器解析令牌-適用 JDBC、記憶體儲存)
- 資源伺服器通過訪問授權伺服器 /oauth/check_token 端點解析令牌需要使用 RemoteTokenServices
- 並且使用 DefaultAccessTokenConverter 來實現令牌資料的儲存
@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
作者:林塬
連結:https://www.jianshu.com/p/6dd03375224d
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。