Skip to content

Commit 9b132c4

Browse files
authored
refactor(docs): update the protect api spring boot instruction (#638)
update the protect api spring boot instruction
1 parent 6067982 commit 9b132c4

File tree

1 file changed

+29
-31
lines changed

1 file changed

+29
-31
lines changed

docs/docs/recipes/protect-your-api/spring-boot.mdx

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,6 @@ import org.springframework.security.oauth2.jwt.Jwt;
128128
129129
public class AudienceValidator implements OAuth2TokenValidator<Jwt> {
130130
131-
private final OAuth2Error oAuth2Error = new OAuth2Error("invalid_token", "Required audience not found", null);
132-
133131
private final String audience;
134132
135133
public AudienceValidator(String audience) {
@@ -139,18 +137,21 @@ public class AudienceValidator implements OAuth2TokenValidator<Jwt> {
139137
@Override
140138
public OAuth2TokenValidatorResult validate(Jwt jwt) {
141139
if (!jwt.getAudience().contains(audience)) {
142-
return OAuth2TokenValidatorResult.failure(oAuth2Error);
140+
return OAuth2TokenValidatorResult.failure(new OAuth2Error("invalid_token", "Required audience not found", null));
143141
}
144142
143+
// Optional: For RBAC validate the scopes of the JWT.
144+
String scopes = jwt.getClaimAsString("scope");
145+
if (scopes == null || !scopes.contains("read:profile")) {
146+
return OAuth2TokenValidatorResult.failure(new OAuth2Error("invalid_token", "Insufficient permission", null));
147+
}
148+
149+
145150
return OAuth2TokenValidatorResult.success();
146151
}
147152
}
148153
```
149154

150-
:::note
151-
For [🔐 RBAC](/docs/recipes/rbac), scope validation is also required.
152-
:::
153-
154155
## Configure Spring Security
155156

156157
Spring Security makes it easy to configure your application as a Resource Server
@@ -173,18 +174,19 @@ import com.nimbusds.jose.proc.SecurityContext;
173174
import io.logto.springboot.sample.validator.AudienceValidator;
174175
import org.springframework.beans.factory.annotation.Value;
175176
import org.springframework.context.annotation.Bean;
177+
import org.springframework.security.config.Customizer;
176178
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
177179
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
178180
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
179181
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
180182
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
181-
import org.springframework.security.oauth2.jwt.Jwt;
182183
import org.springframework.security.oauth2.jwt.JwtDecoder;
183184
import org.springframework.security.oauth2.jwt.JwtValidators;
184185
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
185186
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
186-
import org.springframework.security.web.SecurityFilterChain;
187+
import org.springframework.security.web.DefaultSecurityFilterChain;
187188
189+
@Configuration
188190
@EnableWebSecurity
189191
public class SecurityConfiguration {
190192
@@ -216,15 +218,17 @@ public class SecurityConfiguration {
216218
}
217219
218220
@Bean
219-
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
220-
http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt).cors().and()
221-
.authorizeRequests(customizer -> customizer
222-
// Only authenticated requests can access your protected APIs
223-
// e.g. `http://localhost:3000/` and `http://localhost:3000/profile`.
224-
.mvcMatchers("/", "/secret").authenticated()
225-
// Anyone can access the public profile.
226-
.mvcMatchers("/profile").permitAll()
227-
);
221+
public DefaultSecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
222+
http
223+
.securityMatcher("/api/**")
224+
.oauth2ResourceServer(oauth2 -> oauth2
225+
.jwt(Customizer.withDefaults()))
226+
.authorizeHttpRequests(requests -> requests
227+
// Allow all requests to the public APIs.
228+
.requestMatchers("/api/.wellknown/**").permitAll()
229+
// Require jwt token validation for the protected APIs.
230+
.anyRequest().authenticated());
231+
228232
return http.build();
229233
}
230234
}
@@ -247,20 +251,14 @@ import org.springframework.web.bind.annotation.RestController;
247251
@CrossOrigin(origins = "*")
248252
@RestController
249253
public class ProtectedController {
250-
251-
@GetMapping("/")
252-
public String protectedRoot() {
253-
return "Protected root.";
254-
}
255-
256-
@GetMapping("/secret")
257-
public String protectedSecret() {
258-
return "Protected secret.";
254+
@GetMapping("/api/profile")
255+
public String protectedProfile() {
256+
return "Protected profile.";
259257
}
260258
261-
@GetMapping("/profile")
262-
public String publicProfile() {
263-
return "Public profile.";
259+
@GetMapping("/api/.wellknown/config.json")
260+
public String publicConfig() {
261+
return "Public config.";
264262
}
265263
}
266264
```
@@ -297,7 +295,7 @@ Request your protected API with the Access Token as the Bearer token in the Auth
297295
e.g. execute the `curl` command.
298296

299297
```bash
300-
curl --include 'http://localhost:3000/secret' \
298+
curl --include 'http://localhost:3000/api/profile' \
301299
--header 'Authorization: Bearer <your-access-token>'
302300
```
303301

0 commit comments

Comments
 (0)