I need to hide a specific API for requests coming form IP different to a specific one.
For instance this should work if I try to use it and my IP is 192.168.1.1, but not if my IP is 192.168.1.2.
#RequestMapping(value = "/test/{id}", method = RequestMethod.GET)
#ResponseBody
#IpRestricted
public void download(#PathVariable("id") String id) {
...
}
I read I can make it creating a specific annotation, the one I called "#IpRestricted" in this example, but than how can I proceed? There are better solution to this?
I then realized I can make it without using spring security.
I made an annotation like this:
#Retention(RetentionPolicy.RUNTIME)
public #interface IpRestricted {
}
Than I check the request IP address inside a HandlerInterceptor preHandle method:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod method = (HandlerMethod)handler;
if (method.getMethodAnnotation(IpRestricted.class)!=null) {
if (!request.getRemoteAddr().equals("192.168.1.1")) {
throw new UnauthorizedException("Ip not authorized");
}
}
}
[....]
}
And for the download method:
#RequestMapping(value = "/test/{id}", method = RequestMethod.GET)
#ResponseBody
#IpRestricted
public void download(#PathVariable("id") String id) {
...
}
That's it!
I think the best Spring solution available for this case is the hasIpAddress() method from Spring Security. There are many different ways to configure permissions to your services via Spring Security, and the IP-based solution is also implemented.
Here is a good example of how to set it up.
Related
While trying to get request object in Aspect I found two solutions. I would like to know performance wise which one is better. Here are the details.
I wanted to execute myAspectMethod for all methods annotated by '#myAnnotation'. So where ever spring finds #myAnnotation at method level myAspectMethod will be executed where I am using request object to perform business logic. To get request I found two solutions
Inject request object in Aspect class like
below
#Aspect
public class MyAspect {
#Autowired(required = true)
**private HttpServletRequest request;**
#Around("#annotation(myAnnotation)")
public Object myAspectMethod(ProceedingJoinPoint pjp,
MyAnnotation myAnnotation) throws Throwable {
//....do something with request object
}
}
By sending request object as argument in annotated method and access it thru the argument list received
Access request in Aspect
#RequestMapping(method = { RequestMethod.GET }, value = "/something")
#MyAnnotation
public Object myAnnotatedMethod(**HttpServletRequest request**)
{
//....some business logic
}
#Aspect
public class MyAspect {
#Around("#annotation(myAnnotation)")
public Object myAspectMethod(ProceedingJoinPoint pjp,
MyAnnotation myAnnotation) throws Throwable {
HttpServletRequest request = getRequestArgument(pjp);
....do something with request object
}
private HttpServletRequest getRequestArgument(ProceedingJoinPoint pjp) {
for (Object object : pjp.getArgs()) {
if (object instanceof HttpServletRequest) {
return (HttpServletRequest) object;
}
}
return null;
}
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface MyAnnotation {
}
Between above two different ways of request object usage which one is better from performance perspective? This is important question for which I would like to know the answer.
What are the other pros and cons of each approach.
I'm not sure that the first method works. Even if you can autowire HttpServletRequest this way, you'll have to make your aspect request-scoped.
I think the best option would be to use RequestContextHolder:
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
This method uses a thread-local storage already populated by Spring and doesn't need any changes in your method signature.
The first method did not work.
#Autowired(required = true)
private HttpServletRequest request;
did have the request specific data.
I am currently using the following to extract custom headers from my request
HttpServletRequest request = ((ServletRequestAttributes)
RequestContextHolder.currentRequestAttributes()).getRequest();
request.getHeader("mycustom");
I am working with Spring MVC controller. I have one of my controller as DataController.
I am thinking to add HttpServletRequest as injectable at the top of DataController class using #Inject.
#Controller
public class DataController {
#Inject
HttpServletRequest request;
// .. some code here
#RequestMapping(value = "process", method = RequestMethod.GET)
public #ResponseBody
DataResponse processTask(#RequestParam("workflow") final String workflow) {
String ipAddress = request.getRemoteAddr();
System.out.println(ipAddress);
}
So my question is - Is this the right way to use #Inject? I have never used #Inject before so trying to learn whether the way I am doing it is right or not? Since everytime, who is making call to processTask method, I need to grab its ipAddress whoever is calling that processTask method.
In terms of acquiring HttpServletRequest: semantically speaking, it is definitely wrong.
Reason: HttpServletRequest is an object that is created only when users send requests and is destroyed once the requested user action is completed. You simply can store it that way (from syntax angle) but you shouldn't (from semantic angle). You need to realize that the way how web application works is not exactly same as a desktop application (and don't observe them from the same angle).
Suggestion:
#RequestMapping(value = "process", method = RequestMethod.GET)
public #ResponseBody
DataResponse processTask(#RequestParam("workflow") final String workflow, HttpServletRequest request) {...}
In this way you will get the corresponding request each time the processTask method is called. (HttpServletRequest object is injected by #RequestMapping.)
(If you would like to preserve something through out a session, consider use a bean that is
Suggestion: #Inject private UserService userService;
(assume we have a class registered called UserService.)
You cannot "inject" the HttpServletRequest the only way to use it as far as I know is to added as a method member. Like this:
#Controller
public class DataController {
// .. some code here
#RequestMapping(value = "process", method = RequestMethod.GET)
public #ResponseBody
DataResponse processTask(#RequestParam("workflow") final String workflow,HttpServletRequest request) {
String ipAddress = request.getRemoteAddr();
System.out.println(ipAddress);
}
look also at Spring MVC #AutoWired response not working
In Spring MVC, it is easy to bind request parameter to method paramaters handling the request. I just use #RequestParameter("name"). But can I do the same with request attribute? Currently, when I want to access request attribute, I have to do following:
MyClass obj = (MyClass) request.getAttribute("attr_name");
But I really would like to use something like this instead:
#RequestAttribute("attr_name") MyClass obj
Unfortunately, it doesn't work this way. Can I somehow extend Spring functionality and add my own "binders"?
EDIT (what I'm trying to achieve): I store currently logged user inside request attribute. So whenever I want to access currently logged user (which is pretty much inside every method), I have to write this extra line user = (User) request.getAttribute("user");. I would like to make it as short as possible, preferably inject it as a method parameter. Or if you know another way how to pass something across interceptors and controllers, I would be happy to hear it.
Well, I finally understood a little bit how models work and what is #ModelAttribute for. Here is my solution.
#Controller
class MyController
{
#ModelAttribute("user")
public User getUser(HttpServletRequest request)
{
return (User) request.getAttribute("user");
}
#RequestMapping(value = "someurl", method = RequestMethod.GET)
public String HandleSomeUrl(#ModelAttribute("user") User user)
{
// ... do some stuff
}
}
The getUser() method marked with #ModelAttribute annotation will automatically populate all User user parameters marked with #ModelAttribute. So when the HandleSomeUrl method is called, the call looks something like MyController.HandleSomeUrl(MyController.getUser(request)). At least this is how I imagine it. Cool thing is that user is also accessible from the JSP view without any further effort.
This solves exactly my problem however I do have further questions. Is there a common place where I can put those #ModelAttribute methods so they were common for all my controllers? Can I somehow add model attribute from the inside of the preHandle() method of an Interceptor?
Use (as of Spring 4.3) #RequestAttribute:
#RequestMapping(value = "someurl", method = RequestMethod.GET)
public String handleSomeUrl(#RequestAttribute User user) {
// ... do some stuff
}
or if the request attribute name does not match the method parameter name:
#RequestMapping(value = "someurl", method = RequestMethod.GET)
public String handleSomeUrl(#RequestAttribute(name="userAttributeName") User user) {
// ... do some stuff
}
I think what you are looking for is:
#ModelAttribute("attr_name") MyClass obj
You can use that in the parameters for a method in your controller.
Here is a link a to question with details on it What is #ModelAttribute in Spring MVC?
That question links to the Spring Documentation with some examples of using it too. You can see that here
Update
I'm not sure how you are setting up your pages, but you can add the user as a Model Attribute a couple different ways. I setup a simple example below here.
#RequestMapping(value = "/account", method = RequestMethod.GET)
public ModelAndView displayAccountPage() {
User user = new User(); //most likely you've done some kind of login step this is just for simplicity
return new ModelAndView("account", "user", user); //return view, model attribute name, model attribute
}
Then when the user submits a request, Spring will bind the user attribute to the User object in the method parameters.
#RequestMapping(value = "/account/delivery", method = RequestMethod.POST)
public ModelAndView updateDeliverySchedule(#ModelAttribute("user") User user) {
user = accountService.updateDeliverySchedule(user); //do something with the user
return new ModelAndView("account", "user", user);
}
Not the most elegant, but works at least...
#Controller
public class YourController {
#RequestMapping("/xyz")
public ModelAndView handle(
#Value("#{request.getAttribute('key')}") SomeClass obj) {
...
return new ModelAndView(...);
}
}
Source : http://blog.crisp.se/tag/requestattribute
From spring 3.2 it can be done even nicer by using Springs ControllerAdvice annotation.
This then would allow you to have an advice which adds the #ModelAttributes in a separate class, which is then applied to all your controllers.
For completeness, it is also possible to actually make the #RequestAttribute("attr-name") as is.
(below modified from this article to suit our demands)
First, we have to define the annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PARAMETER)
public #interface RequestAttribute {
String value();
}
Then we need a [WebArgumentResolver] to handle what needs to be done when the attribute is being bound
public class RequestAttributeWebArgumentResolver implements WebArgumentResolver {
public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest nativeWebRequest) throws Exception {
// Get the annotation
RequestAttribute requestAttributeAnnotation = methodParameter.getParameterAnnotation(RequestAttribute.class);
if(requestAttributeAnnotation != null) {
HttpServletRequest request = (HttpServletRequest) nativeWebRequest.getNativeRequest();
return request.getAttribute(requestAttributeAnnotation.value);
}
return UNRESOLVED;
}
}
Now all we need is to add this customresolver to the config to resolve it:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="customArgumentResolver">
<bean class="com.sergialmar.customresolver.web.support.CustomWebArgumentResolver"/>
</property>
</bean>
And we're done!
Yes, you can add your own 'binders' to the request attribute - see spring-mvc-3-showcase, or use #Peter Szanto's solution.
Alternatively, bind it as a ModelAttribute, as recommended in other answers.
As it's the logged-in user that you want to pass into your controller, you may want to consider Spring Security. Then you can just have the Principle injected into your method:
#RequestMapping("/xyz")
public String index(Principal principle) {
return "Hello, " + principle.getName() + "!";
}
In Spring WebMVC 4.x, it prefer implements HandlerMethodArgumentResolver
#Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterAnnotation(RequestAttribute.class) != null;
}
#Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
return webRequest.getAttribute(parameter.getParameterAnnotation(RequestAttribute.class).value(), NativeWebRequest.SCOPE_REQUEST);
}
}
Then register it in RequestMappingHandlerAdapter
I have implemented a REST application with Spring at Java. An example of GET and DELETE requests are as follows:
#RequestMapping(method = RequestMethod.GET)
public
#ResponseBody
List<Configuration> getAllConfigurationsInJSON() {
return new ArrayList<Configuration>(configurationMap.values());
}
#RequestMapping(value = "{systemId}", method = RequestMethod.DELETE)
public void deleteConfiguration(HttpServletResponse response, #PathVariable long systemId) throws IOException {
if (configurationMap.containsKey(systemId)) {
configurationMap.remove(systemId);
response.setStatus(HttpServletResponse.SC_OK);
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
I am searching about Grails and want to rewrite my controller with Grails. I read some articles and it shows that there is no need to write that annotations at Grails. I will just define my clousers and it will render my response to JSON object as like my Spring applicaiton. How can I implement them with closures? (I use IntelliJ IDEA 10.3)
There is nothing in this code that can make use of closures.
In grails it may look the same, or you can put the url mappings in UrlMappings.groovy
I'm trying to get my feet wet with Spring MVC 3.0, and while I can get it to work, I can't seem to handle this particular scenario efficiently.
I have a controller with that handles "/{studyName}/module" prefix, and it looks something like this:-
#Controller
#RequestMapping(value = "/{studyName}/module")
public class ModuleController {
#RequestMapping(...)
public ModelAndView getA(#PathVariable String studyName, ...) {
if (!validStudy(studyName)) { return bad request; }
...
}
#RequestMapping(...)
public ModelAndView getB(#PathVariable String studyName, ...) {
if (!validStudy(studyName)) { return bad request; }
...
}
#RequestMapping(...)
public ModelAndView getC(#PathVariable String studyName, ...) {
if (!validStudy(studyName)) { return bad request; }
...
}
#RequestMapping(...)
public ModelAndView getD(#PathVariable String studyName, ...) {
if (!validStudy(studyName)) { return bad request; }
...
}
}
The problem with this code is, I have the studyName validation scattered all over the methods and possibly in other Controllers' methods too. Is there a way I can perform validation on studyName path variable all in one spot without using something like AOP? How do you handle validation like this?
Thanks.
Right now, it's a little tricky to make this happen automatically, but it is possible. You should use a Bean validation (JSR-303) provider that implements appendix C. Currently that's Apache BeanValidation or Hibernate Validator 4.2 (which is in beta).
Add your chosen bean validation implementation to the classpath. This will be the implementation of JSR-303 that Spring MVC uses.
Second, annotate the method parameter with #Valid and any constraint annotations, like #NonNull.
This will look something like:
public ModelAndView getB(#Valid #NonNull #PathVariable String studyName, ...) {
That should work. You'd then need to check your Spring errors for any problems.
Alternatively, if you don't make use of any other Spring parameters, you can register a validator with an InitBinder like so:
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.setValidator(new StudyNameValidator());
}
Create a class StudyName then have a WebArgumentResolver registered for StudyName and have your validation take place there.
public ModelAndView getA(#PathVariable StudyName studyName){
...
}
public class StudyNameResolver implements WebArgumentResolver{
//have resolveArgument method do validation if resolved to a StudyName
}
I am starting to use spring 3 and I do like your solution of validating in this way:
public ModelAndView getB(#Valid #NonNull #PathVariable String studyName, ...) {
However, once the pathvariable is invalid (in this case studyName = null) how do you catch and display that error?
I have tried to use binding result but it just doesn't work. In addition, do you know how to display the error on the jsp?
Thanks
Create a simple validation class:
public class StudyValidator {
public boolean validateStudy(String studyName) {
//your validate logic here
}
}
then inject it into the ModuleController:
class ModuleController {
private StudyValidator sv = new StudyValidator(); //use spring injection to populate.
boolean validStudy(String studyName) {
return sv.validateStudy(studyName);
}
}
Simples.
Hmmm, not sure if it would work, but you might be able to the #Valid annotation as briefly mentioned in this link on validators.
Good Luck!