Spring Security 與 OAuth2(資源服務器)


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





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM