Spring Security で、アクセスト`クンを編^するリソ`スサ`バ`をg廾する
峻さん、こんにちは。室宝蝕kグル`プの稼-看噛温敬温稼です。
かつてエミュ`との蚯に移れ、150定參貧U狛した書でもウサギと蚯をしているオ`ストラリア屓軒ですが、2015定には竪を盃待議な伏麗として傚蕾叱罎靴討い泙后オ`ストラリアへ唾佩に佩った縞は、ウサギや竪を需かけても芦叟に除篠らない圭が措いかもしれません。
云籾です。
Spring Security でクライアントから鞭け函ったアクセスト`クンを編^して、勣李のリソ`スを卦抜するリソ`スサ`バ`をg廾することが竃栖ます。書指はSpring Securityでアクセスト`クンを編^するやり圭をおしします。
朕肝
Spring Security でアクセスト`クンの編^
ゴ`ル
Spring Security でリソ`スサ`バ`箸g廾します。リソ`スサ`バ`ではクライアントから鞭け函ったアクセスト`クンを編^します。なお、IdPにはKeycloakを旋喘しています。

アクセスト`クンの編^に駅勣なプロパティを協吶する
アクセスト`クンの編^に駅勣なプロパティをapplication.propertiesに協吶します。
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/realms/myrealm或鴛禽遺範^の扮とは離って、アクセスト`クンの編^に駅勣なプロパティは1つです。アクセスト`クンのk佩宀の雨檎鴛を協吶します。ここで協吶したk佩宀がk佩したアクセスト`クンのみを鞭け原けるようになります。
アクセスト`クンを編^する皆艶界顎姻庄岳霞酷庄鉛岳艶姻遺鞄温庄稼を伏撹する
アクセスト`クンを編^する恷弌のコ`ドは參和となります。
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// アクセスト`クン編^
http
.authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
return http.build();
}
}http.authorizeHttpRequests(...)は、クライアントがアクセスしたパスにして、クライアントが癖俳な慙泙鰉个靴討い襪チェックするためのメソッドです。この魁栽は、すべてのパスにアクセスする縞は、アクセスト`クンの編^が或悪である駅勣があります。
http.oauth2ResourceServer(...)は、アクセスト`クンを編^するためのメソッドです。Spring Securityが鬉靴討い襯肌`クンはJWTと、Opaque ト`クンの2つになります。Opaque ト`クン とは、そのト`クンをキ`としてJ辛サ`バ`へい栽わせることで編^するト`クンです。Opaque ト`クン徭悶は採の秤鵑魍屬燭此△修琳佗蹐和卻であることが謹いです。keycloakのアクセスト`クンはJWT侘塀ですので、貧のコ`ドはJWTを編^するようにg廾しています。
貧芝のコ`ドにより、デジタル俸兆の編^に紗えて、參和の編^を佩います。
- 庄壊壊顎艶姻のチェック
覿┐靴討い覆ぐk佩宀がk佩したアクセスト`クンは鰻赫とします。 - 嗤親斛泙離船Д奪
嗤親斛泙俳れたアクセスト`クンを鰻赫とします。
アクセスト`クンのカスタム編^を弖紗する
蒙に弖紗の編^が涙ければ、參貧のコ`ドで噴蛍です。しかし、嶄には弖紗でアクセスト`クンを編^したいこともあるかと房います。一艶霞界鉛看温一がk佩するアクセスト`クンには、そのユ`ザ`に嚥えられたロ`ルが鯉追されています。書指はこのロ`ルを需て、蒙協のロ`ル參翌の魁栽は詳倦するようにしてみましょう。
まずは皆艶界顎姻庄岳霞酷庄鉛岳艶姻遺鞄温庄稼の伏撹のところを俐屎します。
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// アクセスト`クン編^
http
.authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
.oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.decoder(this.jwtDecoder())));
return http.build();
}oauth2.jwt(...)のところで、徭念のJWT DecoderをO協してあげるようにしています。メソッドthis.jwtDecoder()の嶄附は參和の宥りです。
// メンバ篳
@Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
private String issuerUri;
// JwtDecoderを伏撹して卦抜する
private JwtDecoder jwtDecoder() {
// デフォルトのJWT Decoderを伏撹
NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder) JwtDecoders.fromIssuerLocation(issuerUri);
// アクセスト`クンのカスタム編^
OAuth2TokenValidator<Jwt> validators = new DelegatingOAuth2TokenValidator<>(
JwtValidators.createDefaultWithIssuer(issuerUri), // 庄壊壊顎艶姻のチェック、嗤親斛泙離船Д奪
roleValidator() // ロ`ルのチェック
);
jwtDecoder.setJwtValidator(validators);
return jwtDecoder;
}
メソッドの匯佩朕では、デフォルトのJWT Decoderを伏撹しています。哈方にはk佩宀のURIが駅勣になりますので、application.propertiesに協吶したissuer-uriを峺協してあげます。
jwtDecoder.setJwtValidator(...)でアクセスト`クンの編^I尖を峺協することが竃栖ます。峺協する編^I尖には、云栖デフォルトでチェックする仝庄壊壊顎艶姻のチェック々と仝嗤親斛泙離船Д奪々に紗えて、書指弖紗するチェックI尖をまとめて峺協する駅勣があります。
roleValidator()の嶄附は參和の宥りです。
@SuppressWarnings("unchecked")
private OAuth2TokenValidator<Jwt> roleValidator() {
return jwt -> {
Map<String, Object> resourceAccess = jwt.getClaim("resource_access");
Map<String, Object> clientts = (Map<String, Object>) resourceAccess.get(jwt.getClaim("azp"));
List<String> roles = (List<String>) clientts.get("roles");
if (roles.contains("admin")) {
return OAuth2TokenValidatorResult.success();
} else {
OAuth2Error error = new OAuth2Error("unauthorized", "", null);
return OAuth2TokenValidatorResult.failure(error);
}
};
}干敬岳を鞭け函るので、その嶄附を需て、温糸馨庄稼ロ`ルが原嚥されていれば或悪、原嚥されていなければ鰻赫としています。チェック或悪とする魁栽はOAuth2TokenValidatorResult.success()を卦抜します。チェック鰻赫の魁栽はOAuth2TokenValidatorResult.failure(error)を卦抜します。
參貧のg廾により徭念の編^I尖を弖紗することが竃栖ます。adminロ`ルを原嚥されていないユ`ザ`がリソ`スサ`バ`へアクセスしてきたHは、403 Access Denied が卦抜されるようになります。
おわりに
リソ`スサ`バ`迦はアクセスト`クンの編^ぐらいしかやることないので、或鴛禽遺範^を佩うクライアント迦と曳べると酒殆でいいですね。
書指は徭念でアクセスト`クンの編^I尖を弖紗してみました。その匯箭としてロ`ルによるアクセス崙囮を佩っていますが、云栖であればロ`ルによるアクセス崙囮はhttp.authorizeHttpRequests(...)でやった圭が措いです。http.authorizeHttpRequests(...)を聞ったアクセス崙囮は肝指やりたいと房います。
ではまた。
