How can I get the referrer URL in Spring Webflux? - java

How can I get the referrer URL in Spring Webflux?
I tried to look into the header attributes in ServerWebExchange exchange object but could not found the same.
Can someone please help me here.

You just obtain it as a normal header - it doesn't really matter what mechanism you use to do this, since they all have header access.
I tried to look into the header attributes in ServerWebExchange
If you want it on ServerWebExchange, you can definitely obtain it via the following:
serverWebExchange.getRequest().getHeaders().getFirst("referer");
If you want it as a parameter to a normal REST mapping, you can just use #RequestHeader:
#GetMapping("/greeting")
public Mono<String> greeting(#RequestHeader("referer") Optional<String> referer) {
//...
}
Or if you're using a ServerRequest:
public Mono<ServerResponse> greeting(ServerRequest request) {
String referer = request.headers().firstHeader("referer");
//...
}

Related

Adding another MediaType to REST api endpoint that is used by other clients

In my app I am sharing REST api using Spring MVC, which users may use in their custom apps. Let's say I have an endpoint in Controller class:
#GET
#Path("/getNumber")
#Produces({ MediaType.TEXT_PLAIN })
public String getNumber(Long id) {
return service.getNumber(id);
}
which response is available only as TEXT_PLAIN. What would happen, if for example one of the client say that his app will not work when he gets response as plain text and that the endpoint should return json/or should have possibility to return response in json? So when I add another MediaType to annotation #Produces, may that cause problems with other users custom apps using this endpoint? Because for ex. in their apps, client may be expecting response as plain text, and by getting response as json, response will not be handled correctly?
If adding this MediaType may cause problems, what can I do to take into account users custom apps using this endpoint? Should I create similar endpoint, but this one will have MediaType APPLICATION_JSON, or both, with added for ex. "/v2" in endpoint path, or is there some better solution for that?
#GET
#Path("/v2/getNumber")
#Produces({ MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON })
public String getNumber(Long id) {
return service.getNumber(id);
}
No need to create multiple endpoints. You can define multiple mediaTypes in #Produces.
Inorder to decide which MediaType should be sent as response, Client has to set the type of MediaType they are expecting in the "Accept" header when making the request.
Based on this "Accept" header you can decide what content-type to return.
you can use "consume" keyword for Multiple media type
#GET(value = "/configuration", consumes = {
MediaType.APPLICATION_JSON_VALUE,
MediaType.MULTIPART_FORM_DATA_VALUE
})
public String setConfiguration(#RequestPart MultipartFile file,
#RequestBody Configuration configuration)

Derive content types from request and return value in Spring boot application

In Spring boot application, through Aspect, I would like the content type of HttpRequest and HttpResponse. Basically, I would like to determine if the associated content types are application/json.
So far, I have written the following code snippet:
public void captureRequest(JoinPoint joinPoint, Object returnValue) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
.currentRequestAttributes())
.getRequest();
String requestContentType = ???? <--CANNOT UNDERSTAND WHAT TO WRITE HERE
if(requestContentType.equals("application/json") {
...
}
String responseContentType = ??? <-- CANNOT UNDERSTAND HOW TO DERIVE CONTENT TYPE FROM RETURN VALUE
}
EDIT:
In this regard, after going through a few articles here on SO, I thought, there would be a key: Content-Type as one of the keys in headers. But when I printed the header names as follows, I did not find any key Content-Type. I found only the following keys:
Cookie
Accept
Connection
User-Agent
Sec-Fetch-Site
Sec-Fetch-Dest
Host
Accept-Encoding
Sec-Fetch-Mode
Accept-Language
As mentioned, in the above code snippet, I would like to derive content types of request and return value. Could anyone please help here?

Jooby custom interceptor

I have the following problem:
I have a rest API on a jooby server. I want to create a custom annotation interceptor which handles particular requests and validates the oauth token in the header.
#GET
#Path("current")
#AuthenticationTokenValidator
public Result getCurrentUser(final Request req) {
...
Or for an entire controller
#Path("/v1/some_route")
#Consumes("json")
#Produces("json")
#AuthenticationTokenValidator
public class SomeController {
How can I do that? Thanks in advance!
You need a filter and then ask for route attributes. Something similar to this:
{
use("*", (req, rsp, chain) -> {
String value = req.route().attr("authenticationTokenValidator");
// your code goes here
});
}
Not sure if the annotation at the class level is supported.
Checkout the documentation about route attributes, there is a similar example.

MVC - Accept JSON when content-type is custom (not application/json)

I am trying to implement the Content-Security-Policy-Report-Only Header for my website.
In order to do that, i need a controller that will accept the browsers POST-Request - which will send data about the violation in form of JSON. This request, however, seems to specify the Content-Type as application/csp-report instead of application/json (side note: Why the hell??).
This apparently causes Spring to refuse the request - it seems like the usage of #RequestBody makes spring only accept requests that are of Content-Type "application/json".
Even when i specifically set the value consumes of the #RequestMapping annotation to application/csp-report it still does not accept the request.
I have gone as far as using a filter to wrap the request with HttpServletRequestWrapper - which seems to be the common way of modifying the behavior of a request.
I have overwritten all of these methods: getContentType(), getHeader(String), getHeaders(String) to return "application/json".
But the request still does not go through.
What am i missing here?
Are there any better solutions to this that
do not require me to do magic with the request?
I wouldn't even
mind parsing the JSON manually, can i somehow accept it as plain
String instead?
According documentation on #RequestBody annotation,
The body of the request is passed through an HttpMessageConverter to resolve the method argument depending on the content type of the request
What that means is Spring Framework defines a specialized API for defining how certain MediaTypes are converted into certain Java types when used as parameters to REST endpoints.
Here is a pretty good article showcasing these capabilities.
There are a great deal of builtin Spring converters that you may be able to just configure and use if your media format can be mapped to their respective media formats. Specifically for your case, you should look at one of the converters available in spring.converter.json package. In simplest case, making it work should be as simple as:
HttpMessageConverter converter = new <JsonConverterOfYourChoice>(JsonMapper);
converter.getSupportedMediaTypes().add(new MediaType("application", "csp-report"));
And then registering such converter into a spring's configuration as you do.
Other available converter types include:
StringHttpMessageConverter
ObjectToStringHttpMessageConverter (if you have already configured Spring's ConversionService to read your desired types from String)
ByteArrayHttpMessageConverter
FormHttpMessageConverter
Various XML-based converters living in spring.converter.xml package
AllEncompassingFormHttpMessageConverter (converter built on top of Form converter and capable of handling XML and JSON as well)
ProtobufHttpMessageConverter
Atom/RSS feed message converters.
Finally, if none of the above does not apply for you, you can make and register your own HttpMessageConverter implementation.
Building M. Prokhorov's answer into a complete snippet, this code worked for me to add application/csp-report as a JSON message converter (using Jackson) in Spring Boot:
#Bean
public WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
super.extendMessageConverters(converters);
final List<MediaType> cspReportMediaTypes =
Collections.singletonList(new MediaType("application", "csp-report"));
final HttpMessageConverter<Object> cspReportConverter =
new MappingJackson2HttpMessageConverter() {
#Override
public List<MediaType> getSupportedMediaTypes() {
return cspReportMediaTypes;
}
};
converters.add(cspReportConverter);
}
};
}
The other answers helper me figuring out what was going on with #ResponseBody.
CSP reporting is still relatively new and not quite standardized among browsers:
The CSP2 spec states that CSP report requests need to use a
content-type header of application/csp-report. In my sample, I
observed four different content-type headers:
application/x-www-form-urlencoded
application/json
application/csp-report
application/json; charset=UTF-8
What to Expect When Expecting Content Security Policy Reports
So an alternative, to accept any kind of content type, is to read the input stream directly from the HttpServletRequest instead of using #ReponseBody with a message converter.
For example, in Kotlin:
#PostMapping(path = [CSP_REPORT_URL])
fun reportFrontendError(
request: HttpServletRequest
): ResponseEntity<Void> {
val body = request.inputStream.bufferedReader().use { it.readText() }
// ...
return ResponseEntity(HttpStatus.OK)
}

Spring 3.x - how do I redirect from a mapping that returns data?

I have a method in my controller like this:
#RequestMapping(value="getData", method=RequestMethod.GET)
#ResponseBody
public List<MyDataObj> getData()
{
return myService.getData();
}
The data is returned as JSON or xsl, depending on the request.
If the person making the request is not authorized to access the data I need to redirect the user to a "not authorized" page, so something like this:
#RequestMapping(value="getData", method=RequestMethod.GET)
#ResponseBody
public List<MyDataObj> getData()
{
if (!isAuthorized())
{
// redirect to notAuthorized.jsp
}
return myService.getData();
}
All the examples I've seen using Spring require the method to return either a String or a ModelAndView. I thought about using HttpServletResponse.sendRedirect() but all my JSPs are under WEB-INF and can't be reached directly.
How can I deny access gracefully to the data request URL?
A more elegant solution may be to use a HandlerInterceptor which would check for authorization, blocking any requests which are not permitted to proceed. If the request then reaches your controller, you can assume it's OK.
The answer is below. But your particular case would rather to handle with other approach.
#RequestMapping(value = "/someUrl", method = RequestMethod.GET)
#ResponseBody
public Response someMethod(String someData, HttpServletResponse response){
if(someData=="redirectMe"){
response.sendRedirect(ppPageUrl);
}
...
}
Another approach is filter. You can move all security logic into filter and keep clean code in controllers.
Pretty simple:
Send a error status to the client
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
and handle the same with you ajax callback handler and redirect. :)

Categories