raphaeldl / spring-webflux-security-jwt Goto Github PK
View Code? Open in Web Editor NEWA JWT authorization and authentication implementation with Spring Reactive Webflux, Spring Boot 2 and Spring Security 5
A JWT authorization and authentication implementation with Spring Reactive Webflux, Spring Boot 2 and Spring Security 5
Should AuthorizationHeaderPayload be using getResponse()?
`public class AuthorizationHeaderPayload {
public static Mono<String> extract(ServerWebExchange serverWebExchange) {
return Mono.justOrEmpty(serverWebExchange.getResponse()
.getHeaders()
.getFirst(HttpHeaders.AUTHORIZATION));
}
}`
Why do i get this message when i use postman. Curl is working perfectly though.
Even /api/guest api fails.
With following stacktrace:
https://pastebin.com/hbrkyWGi
How to make APIs return 401 instead of failing with 500, if no any creds were specified./
I think ServerHttpBearerAuthenticationConverter
should be used only for preparing the token for further processing:
Mono.justOrEmpty(serverWebExchange)
.map(JWTAuthorizationPayload::extract)
while authenticating the token:
map(VerifySignedJWT::check)
.map(UsernamePasswordAuthenticationFromJWTToken::create)
is the responsibility of JWTReactiveAuthenticationManager
By the way - instead of providing own implementation of JWTAuthorizationWebFilter
just do:
@Component
public class JWTAuthenticationWebFilter extends AuthenticationWebFilter {
public JWTAuthenticationWebFilter(final JWTAuthenticationManager authenticationManager,
final ServerHttpBearerAuthenticationConverter converter,
final UnauthorizedAuthenticationEntryPoint entryPoint) {
super(authenticationManager);
setAuthenticationConverter(converter);
setAuthenticationFailureHandler(new ServerAuthenticationEntryPointFailureHandler(entryPoint));
setRequiresAuthenticationMatcher(new JWTHeadersExchangeMatcher()); //this is necessary to match headers. Requests without JWT header should not be taken into account by this filter
}
private static class JWTHeadersExchangeMatcher implements ServerWebExchangeMatcher {
@Override
public Mono<MatchResult> matches(final ServerWebExchange exchange) {
return Mono.just(exchange)
.map(ServerWebExchange::getRequest)
.map(ServerHttpRequest::getHeaders)
.filter(h -> h.containsKey("some JWT header"))
.flatMap($ -> MatchResult.match())
.switchIfEmpty(MatchResult.notMatch());
}
}
}
And don't forget to set:
http
.exceptionHandling()
.authenticationEntryPoint(new UnauthorizedAuthenticationEntryPoint ())
.and()
where
@Component
public class UnauthorizedAuthenticationEntryPoint implements ServerAuthenticationEntryPoint {
@Override
public Mono<Void> commence(final ServerWebExchange exchange, final AuthenticationException e) {
return Mono.fromRunnable(() -> exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED));
}
}
otherwise SpringSecurity will still display BasicAuth on requests without headers
Use that in another request:
$ curl -v -H "Authorization: Authorization: Bearer eyJhbGciOiJIUzI1Ni....." localhost:8080/api/admin
You should be able to consume the API
have to be:
$ curl -v -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni....." localhost:8080/api/admin
Sorry I am new to this whole Spring Security scenario, and also to reactive programming. I am trying to run this application, and I am not sure how I can login to this application and generate the JWT Token for furthur requests to the resource server
First off thank you for this great example.
I think you forgot to add the @EnableReactiveMethodSecurity
annotation on your SecuredRestApplication
. I was playing around a bit with your code and removing the ADMIN role from the user setup did not prevent me from accessing the /api/admin endpoint.
@Bean
public MapReactiveUserDetailsService userDetailsRepository() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("user")
.roles("USER")
.build();
return new MapReactiveUserDetailsService(user);
}
Then I generated a new token Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwicm9sZXMiOiJST0xFX1VTRVIiLCJpc3MiOiJyYXBoYS5pbyIsImV4cCI6MTU2NzY3OTY3OX0.C67PZ_YX2Zm1_YDMnVgqoxNXCEd4iKOhTM9EdiEA5WI
(content can be checked via https://jwt.io/ and verified with the default secret of your app).
This will then still allow me to call the admin endpoint:
$ http -v :8080/api/admin "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwicm9sZXMiOiJST0xFX1VTRVIiLCJpc3MiOiJyYXBoYS5pbyIsImV4cCI6MTU2NzY3OTY3OX0.C67PZ_YX2Zm1_YDMnVgqoxNXCEd4iKOhTM9EdiEA5WI"
GET /api/admin HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwicm9sZXMiOiJST0xFX1VTRVIiLCJpc3MiOiJyYXBoYS5pbyIsImV4cCI6MTU2NzY3OTY3OX0.C67PZ_YX2Zm1_YDMnVgqoxNXCEd4iKOhTM9EdiEA5WI
Connection: keep-alive
Host: localhost:8080
User-Agent: HTTPie/0.9.8
HTTP/1.1 200 OK
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: application/json;charset=UTF-8
Expires: 0
Pragma: no-cache
Referrer-Policy: no-referrer
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1 ; mode=block
transfer-encoding: chunked
[
{
"message": "Hello Admin!",
"name": "Admin"
}
]
When adding the @EnableReactiveMethodSecurity
annotation, I get the following, as expected:
HTTP/1.1 403 Forbidden
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: text/plain
Expires: 0
Pragma: no-cache
Referrer-Policy: no-referrer
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1 ; mode=block
transfer-encoding: chunked
Denied
Hi, How can we generate the auth token?
how to use AccessDecisionManager in your project ?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.