I was using spring annotations to map url to method, as shown in below code.
#Controller
public class HomeController {
#RequestMapping(value="/admin/dashboard.htm" ,method=RequestMethod.GET)
public String dashboard(HttpServletRequest request,HttpServletResponse response) {
.....
return "success";
}
}
I have removed spring annotations by spring xml.
Previously I was accessing method using
localhost:8888/admin/dashboard.htm url.
Now without annotations I need to use localhost:8888/home/dashboard.htm url to access method. I am using Controller Class Name HandlerMapping now.
What i need is, i want to access dashboard method using previous url localhost:8888/admin/dashboard.htm without annotations.
You should have a look at BeanNameUrlHandlerMapping (or take a lookControllerBeanNameHandlerMapping) described in Spring 2.5, which seems to do, what you want. But Why would anyone want that?
Related
we have a spring boot app with a java package that has spring controllers with endpoints for admin-like functionality. right now they all start with the same request mapping.
so one way i could do authorization of every endpoint in the package is by WebSecurityConfigurerAdapter implementation...
http.authorizeRequests()
.antMatchers("/admin/**").access("hasRole('ADMIN')")
but i was thinking it would be nice to use AOP somehow to target the package of the admin controllers to PreAuthorize all controller methods in the package. just in case someone on the project creates a new controller in the proejct with a different request mapping it would automatically be projected. also, if we decided to PreAuthorize at the #Service level instead of the controller level then this way could be used as well.
so, is it possible to PreAuthorize at the package level with AOP or some other way?
Spring provides default AOP interceptor for #Secured and #PreAuthorized annotations, but it works only on class or method level, and AFAIK not intended to be expanded to package level.
To put it simply, Spring intercepts calls to certain methods or all class methods with these annotations and check whether SecurityContextHolder holds Authority object and whether its collection of GrantedAuthority matches any of the annotation's value field values. So, you can do the same thing using AOP, for example like this:
#Aspect
#Component
public class AdminServiceAOPAuthorization {
private static final List<String> ALLOWED_ROLES = List.of("ADMIN", "SUPER_ADMIN");
#Pointcut("within(com.example.service.admin.*)") // <- any method in any class of the package
public void adminServiceLayer() {}
#Before("adminServiceLayer()")
public void authorize(JoinPoint jp) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
// throw some exception depending on the logic
}
boolean authorized = authentication.getAuthorities().stream()
.anyMatch(ga -> ALLOWED_ROLES.contains(ga.getAuthority()));
if (!authorized) {
throw new AccessDeniedException("Access denied");
// log or whatever
}
}
}
For better performance I'd advise to use it at the service layer to let Spring create proxy using implemented interface (if you use them, of course) instead of proxying controller class.
I have several controller functions separated by role, and instead of doing role validation in each controller method, I found that it seems to be able to get done by using Aspect, however something isn't right in my implementation as the code in Aspect never runs
Annotation:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface ForMerchantOnly {}
Aspect:
#Aspect
#Configuration
public class ForMerchantOnlyAspect {
private static final Logger logger = LogManager.getLogger(ForMerchantOnlyAspect.class);
#Before("#annotation(com.example.api.annotation.ForMerchantOnly) && args(request)")
public void before(HttpServletRequest request) throws ServiceException {
if (!(request instanceof HttpServletRequest)) {
throw new RuntimeException("request should be HttpServletRequesttype");
}
String domain = request.getServerName();
System.out.println("Aspect showing domain " + domain);
// -- other code
}
}
Controller
#ForMerchantOnly
#GetMapping("/list")
public ResponseEntity<ApiResp> list() {
System.out.println("Show something");
return ResponseEntity.ok().body();
}
I'm assuming when i call controller /list method via chrome browser, it would hit the code in ForMerchantOnlyAspect but it just went into the controller method directly. Am I missing something?
The Aspect was not working as it could not find a matching joinpoint . There are no controller methods that has annotation #ForMerchantOnly and has an argument of type HttpServletRequest
From the documentation :
args: Limits matching to join points (the execution of methods when
using Spring AOP) where the arguments are instances of the given
types.
Following aspect may be used for the requirement . Scoping designator within will set the scope to advice.
#Before("#annotation(com.example.api.annotation.ForMerchantOnly) && within(com.example.api..*)")
public void before() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
.getRequest();
System.out.println("Aspect showing domain " + request.getServerName());
}
Also note that an Aspect is better annotated with #Component and #Configuration be used for configurations.
You may also have a look at Method Security of Spring security framework , which lets to secure a method with annotations.
From the documentation
From version 2.0 onwards Spring Security has improved support
substantially for adding security to your service layer methods. It
provides support for JSR-250 annotation security as well as the
frameworkâs original #Secured annotation. From 3.0 you can also make
use of new expression-based annotations. You can apply security to a
single bean, using the intercept-methods element to decorate the bean
declaration, or you can secure multiple beans across the entire
service layer using the AspectJ style pointcuts.
I want to create an custom method argument Resolver using Spring WebFlux. I am following link but its seem to be not working.
I am able to create the custom argument resolver using WebMvc.
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
public class MyContextArgumentResolver implements HandlerMethodArgumentResolver {
#Override
public boolean supportsParameter(MethodParameter parameter) {
return MyCustomeObject.class.isAssignableFrom(parameter.getParameterType())
}
#Override
public Mono<Object> resolveArgument(MethodParameter parameter, BindingContext bindingContext,
ServerWebExchange exchange) {
.....
return Mono.just(new MyCustomeObject())
}
Please note that i am using HandlerMethodArgumentResolver from .web.reactive. package.
My AutoConfiguration file look like
#Configuration
#ConditionalOnClass(EnableWebFlux.class) // checks that WebFlux is on the class-path
#ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)//checks that the app is a reactive web-app
public class RandomWebFluxConfig implements WebFluxConfigurer {
#Override
public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
MyContextArgumentResolver[] myContextArgumentResolverArray = {contextArgumentResolver()};
configurer.addCustomResolver(myContextArgumentResolverArray );
}
#Bean
public MyContextArgumentResolver contextArgumentResolver() {
return new MyContextArgumentResolver ();
}
My spring.factories looks like
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.XXXX.XXX.XXX.RandomWebFluxConfig
Please note that above configuration is part of the jar which is added in Spring WebFlux Boot project enabled using #EnableWebFlux .
It seems you're conflating two different problems here.
First, you should make sure that your method argument resolver works in a regular project.
For that, you need a #Configuration class that implements the relevant method in WebFluxConfigurer. Your code snippet is doing that but with two flaws:
Your configuration is using #EnableWebFlux, which is disabling the WebFlux auto-configuration in Spring Boot. You should remove that
it seems you're trying to cast a list of MethodArgumentResolver into a single instance and that's probably why things aren't working here. I believe your code snippet could be just:
configurer.addCustomResolver(contextArgumentResolver());
Now the second part of this question is about setting this up as a Spring Boot auto-configuration. I guess that you'd like WebFlux applications to automatically get that custom argument resolvers if they depend on your library.
If you want to achieve that, you should first make sure to read up a bit about auto-configurations in the reference documentation. After that, you'll realize that your configuration class is not really an auto-configuration since it will be applied in all cases.
You should probably add a few conditions on that configuration like:
#ConditionalOnClass(EnableWebFlux.class) // checks that WebFlux is on the classpath
#ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) // checks that the app is a reactive web app
I have written some RESTful webservices using Spring Framework (by reading posts online / video tutorials etc.) , however I still have some doubts.
When we write a web-application using Spring MVC module we use controller code, similar to below:
#Controller
public class SimpleController {
#RequestMapping("/welcome")
ModelAndView handleIncomingWelcomeReq() {
ModelAndView mw = new ModelAndView("WelcomePage","welcomeKey","WelcomeKey's value!");
return mw;
}
}
In the above code there is ModelAndView object which this controller returns, and this can be invoked like this URL:
http://localhost:8080/contextRoot/welcome
Now, if we exclude the "view" part and return just the model doesn't it act like a web service?
So my doubt is, in Spring do we used the same API/jar's to create web-application or RESTful web services?
The things which I read is that for Spring REST support, it has annotation #RestController annotation (which itself is like #Contoller + #ResponseBody annotations).
So what is the difference in which the implementation of REST WS and web-applications differs in Spring Framework?
Can anyone help me understand this?
Yes we can write RestService & web application using Spring. Use #RestController to expose a REST service and #Controller for web application.
#RestController is a meta-annotation with #Controller and #ResponseBody. #Controller will search through the registered ViewResolvers, whereas #RestController will not.
#Controller
public class SimpleController {
#RequestMapping("/welcome", method = RequestMethod.GET, produces="application/json")
public #ResponseBody JSONObject handleIncomingWelcomeReq() {
JSONObject j = new JSONObject();
j.put("welcomeKey", "WelcocmeKey's value!");
return j;
}
Here is the code which returns response in json mostly user id Rest Apis.
I would suggest to use #Controller instead of #RestController, as #RestController, won't scan your views. So, in case if your application has it's own views and also needs to expose it's services, you can use #Controller along with the #ResponseBody annotations, with output as JSON.
Another option is to have completely different URL for RESTful webservices, where a different controller will handle the request. These different controllers can be annotated with #RestController.
I have implemented my GWT application using Spring + GWTP.
I want to access HttpServletRequest object into my ActionHandler class.
The ServerModule is Spring Configuration class (using #Configuration Annotation).
Now problem is how can I inject the current HttpServletRequest, ServletContext, ServletConfig in my ActionHandler using Spring.
Following is the definition of ServerModule:
#Configuration
#Import(DefaultModule.class)
public class ServerModule extends HandlerModule
{
#Bean
public UserVerficationActionHandler getUserVerificationActionActionHandler()
{
return new UserVerficationActionHandler();
}
}
In above Example I just want to inject the HttpServletRequest using Spring.
Any guidance on this highly appreciated.
Thanks.
The RequestProvider is your solution. It's a class in gwt-dispatch-server jar.
DefaultModule provides the RequestProvider bean so that you can just inject it into places you need it.
Take a look at the sourcec code for com.gwtplatform.dispatch.server.spring.configuration.DefaultModule which creates the RequestProvider as a DefaultRequestProvider which then defers to RequestContextHolder to do the work.
See the link for what you need to add to your web.xml to get this to work.