I have a project in which i am using Spring mvc 4 and i need to include there apache shiro security. I've tried to search over the web for a solution for my problem but didn't managed to fins something. Although there is a guide at Shiro's web site, but this example is only for xml configured Spring project, and my project doesn't contain any xml at all, and when i am trying to configure Shiro with annotation only it fails.
When i run this project i have an access to all of my end points, and non of them is being restricted by Shiro.
I guess that my configuration is wrong but i am unable to figure out which part of it is wrong.
I am not allowed to use Spring boot (i know that there is examples for that).
here is my configuration class:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.myproject.menu")
public class AppConfiguration extends WebMvcConfigurerAdapter{
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("/");
}
#Bean(name="shiroFilter")
public ShiroFilterFactoryBean shiroFilter (){
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setLoginUrl("/MenuTest/login");
shiroFilter.setFilterChainDefinitions("/MenuTest/init=anon");
shiroFilter.setFilterChainDefinitions("/MenuTest/**=authc");
shiroFilter.setSecurityManager(realm());
return shiroFilter;
}
private DefaultWebSecurityManager realm(){
DefaultWebSecurityManager realm = new DefaultWebSecurityManager();
return realm;
}
}
Thx in advance!
Take a look at the 1.4.0 (RC2) release. There is updated Spring and Spring-Boot support.
And examples in the source tree:
https://github.com/apache/shiro/tree/master/samples/spring-mvc
Related
I have a Spring Boot application which acts as a server for my frontend, built by webpack and included into my spring boot web archive.
I use webjars to access my frontend scripts and contents.
But there is one problem. To access webjars resources I need to use pathes like:
/webjars/jar-file-name/resource-name.ext
When in my react-js frontend code I use relateve pathes:
/resource-name.ext
I want to rebind paths of webjars to serve all resources /** from /webjars/jar-file-name
I have used this do to do it https://www.webjars.org/documentation#springmvc, but this seems to not work with Spring Boot
#Configuration
#EnableWebMvc
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
super.addResourceHandlers(registry);
registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/webjars/jar-file-name/");
}
}
It should work with Spring MVC, but don't work in Spring Boot.
Could you please advice the right way to do it?
I think the following code would resolve your issue:
#Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
Here is my static content serving URL for bootstrap 3.1.0 from tutorial: http://localhost:8080/bootstrap/3.1.0/css/bootstrap.min.css
Playing around with Spring Boot + MVC with static HTML pages, while noticed this thing:
Firstly, what I have:
Index controller:
#Controller
public class IndexController {
#RequestMapping("/")
public String index() {
return "index.html";
}
#RequestMapping("/{path:[^\\.]+}/**")
public String forward() {
return "forward:/";
}
}
The Html file is:...\src\main\resources\static\index.html
So when my main application class is:
#SpringBootApplication
public class MyApplication extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
Everything works well and in default path: localhost:8080\ I get index.html page content
But if I annotate Application class with #EnableWebMvc
#SpringBootApplication
#EnableWebMvc
public class MyApplication extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
I get exception: javax.servlet.ServletException: Could not resolve view with name 'index.html' in servlet with name 'dispatcherServlet'
But according to this spring doc it is a valid configuration.
Maybe someone can explain me why? Do I understand something wrong?
According to spring-boot's docs
The auto-configuration adds the following features on top of Spring’s defaults:
Static index.html support.
...
If you want to keep Spring Boot MVC features, and you just want to add
additional MVC configuration (interceptors, formatters, view
controllers etc.) you can add your own #Configuration class of type
WebMvcConfigurerAdapter, but without #EnableWebMvc. If you wish to
provide custom instances of RequestMappingHandlerMapping,
RequestMappingHandlerAdapter or ExceptionHandlerExceptionResolver you
can declare a WebMvcRegistrationsAdapter instance providing such
components.
So by adding #EnableWebMvc you just disable what spring-boot autoconfiguring for you. Namely static index.html support.
Actually I think when you choose to use spring boot you should use the default config of spring Boot. It means you just have to edit the file application.properties. Now if you use spring mvc, you have to provide your own servlet. So I think mixing up the to is not a good idea. Either you use spring Boot wiht no much config to do or you use spring mvc and you make all the necessary config.
According to Spring Boot MVC structure, you should locate your html file in the templates folder. Then will be visible for Spring Boot
src\main\resources\templates\index.html
I noticed Spring Boot Actuator only works if your application uses Spring MVC (DispatcherServlet) to handle endpoints. By default, this servlet is included if you add the module spring-boot-starter-web into your project.
Once this servlet exists, the class EndpointWebMvcAutoConfiguration customize the Spring MVC to support endpoints and other management properties.
For record, my application implements a Vaadin Servlet to navigate on screens, so is there any way to enable Spring Boot Actuator in this case?
You won't be able to reuse the EndpointWebMVCAutoConfiguration class as it is explicitly conditionnal on DispatcherServlet.class. If you look at the implementation, you'll see that the Actuator has a lot of dependencies on Spring MVC.
It would be a little ballzy but you could consider implementing your own autoconfiguration class inspired by EndpointWebMVCAutoConfiguration.
I wish you good luck if you go down that path ;)
You can have both. If you have a VaadinServlet, you can try with something like:
#SpringBootApplication
public class AdminApplication {
#Bean
public ServletRegistrationBean<SpringVaadinServlet> springVaadinServlet() {
SpringVaadinServlet servlet = new SpringVaadinServlet();
ServletRegistrationBean<SpringVaadinServlet> registrationBean = new ServletRegistrationBean<>(servlet, "/your-web-app/*");
registrationBean.setLoadOnStartup(1);
registrationBean.setName("VaadinServlet");
return registrationBean;
}
}
#SpringUI(path = "/")
public class VaadinUI extends UI {
...
}
Notice the need for a registration name, a custom servlet mapping URL, and custom path in the #SpringUI annotation.
You can find a running demo here.
Does anyone have any reference project with Spring-boot and Tapestry5? I can't seem to find any samples.
I have diificulties in configuring the tapestry bean & Context using a #configuration class without an web.xml.
This should be what you're looking for https://github.com/trust-wenderson/tapestry-spring
I've been looking for such an example myself, and I happen to have found one today:
https://github.com/code8/tapestry-boot
The tapestry-boot library implements following features:
bootstraps tapestry framework inside embedded servlet container managed by spring-boot
provides injection of spring-services into tapestry-services
provides injection of tapestry-services into spring-services
To use tapestry-boot simple marks tapestry application module with
#TapestryApplication annotation.
See DemoApplicationTests.
This works for me:
Register TapestrySpringFilter
#Bean
public FilterRegistrationBean tapesSpringFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new TapestrySpringFilter());
registration.setName("app");
registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
return registration;
}
Add context aprameters to application.yml
server:
context_parameters:
tapestry:
use-external-spring-context: true
app-package: com.test.admin
development-modules: ...
qa-modules: ...
I also had to use executable War to avoid problems with loading static files.
Perhaps this approach will not allow you to access the tapestry beans from the spring context.
I have a following project structure
-Project
|-config
| |-modules
| |-admin
| |-web
|- platform
Platform is the project that contains the spring-boot start class,
Platform has a dependency on config and config had dependencies on everything in the directory modules
Platform is also the module that gets started with the mvn spring-boot:run command.
The thing I am trying to accomplish is that the modules admin and web (both web apps) have their own mapping like
/admin
/web
The following code represents an controller in the admin module, the web module also contains a similar controller (thats the point)
#Controller
public class AdminController {
#RequestMapping("/")
public String adminController() {
return "admin";
}
}
Here some code for the configuration of the admin module
#Configuration
public class Config implements EmbeddedServletContainerCustomizer {
#Autowired
protected WebApplicationContext webApplicationContext;
#Autowired
protected ServerProperties server;
#Autowired(required = false)
protected MultipartConfigElement multipartConfig;
protected DispatcherServlet createDispatcherServlet() {
AnnotationConfigEmbeddedWebApplicationContext webContext = new AnnotationConfigEmbeddedWebApplicationContext();
webContext.setParent(webApplicationContext);
webContext.scan("some.base.package");
return new DispatcherServlet(webContext);
}
protected ServletRegistrationBean createModuleDispatcher(DispatcherServlet apiModuleDispatcherServlet) {
ServletRegistrationBean registration =
new ServletRegistrationBean(apiModuleDispatcherServlet,
"/admin");
registration.setName("admin");
registration.setMultipartConfig(this.multipartConfig);
return registration;
}
#Bean(name = "adminsServletRegistrationBean")
public ServletRegistrationBean apiModuleADispatcherServletRegistration() {
return createModuleDispatcher(createDispatcherServlet());
}
public void customize(ConfigurableEmbeddedServletContainer container) {
container.setContextPath("/admin");
}
}
Something similar goes for the web module
I have tried the implement the some of the given answers.
Using multiple dispatcher servlets / web contexts with spring boot
Spring Boot (JAR) with multiple dispatcher servlets for different REST APIs with Spring Data REST
And lots of googling
When I let the component scan, scan both modules (removing the ComponentScan filter)
I get an a Ambiguous mapping found exception, saying that both controller methods dispatch to the same path "/"
But when disabling the component scan on one of the modules, then indeed the admin modules get mapped to /admin.
when I disable both controllers, I see that the /web and /admin dispatchServlets get mapped.
So I understand the exception but I dont understand how to resolve this.
For me its a must that I can do this per module and I dont want to map it using
#RequestMapping("/admin")
on the controller class
I also tried specifying the contextPath and servletPath in the application.properties
So my question is: what would be the best approach to reach my goal, or am I trying to use spring-boot for something it was not ment for.
Edit
A Proof of concept would be nice
So I found the solution.
You can take a look here at this link
You`ll have to register the dispatcher servlets in the main application and dont use the #SpringBootApplication annotation.
For a complete example just checkout the project and check the code
EDIT: later this week ill provide a detailed answer
What you should do is that put your AdminController and WebController in separate packages.
some.base.admin.package
some.base.web.package
And in the corresponding configurations scan only your required package to register the DispatcherServlet
Admin Config
webContext.scan("some.base.admin.package");
Web Config
webContext.scan("some.base.web.package");
This way in the corresponding WebApplicationContext for each DispatcherServlet only one mapping will be available for "/"