1. 程式人生 > >Spring Security 與 OAuth2(資源伺服器)

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




作者:林塬
連結:https://www.jianshu.com/p/6dd03375224d
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。