access HTML pages using spring boot - spring-mvc

I am trying to serve HTML pages using spring boot , i don't want to use Thyme leaf as i just have static HTML pages note that serving js and css files is working good from /resources/static/ but if i have a controller like below
#Controller
public class DefaultConfiguration {
#RequestMapping(value = "/login")
public ModelAndView login() {
return new ModelAndView("login");
}
}
and
#Configuration
public class MvcConfiguration extends WebMvcConfigurerAdapter {
#Bean
public ViewResolver getViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/");
resolver.setSuffix(".html");
return resolver;
}
#Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
i always get error
Circular view path [/login.html]: would dispatch back to the current handler URL [/login.html] again

Why do you need to configure MvcConfiguration? If you don't have thyme leaf / free marker / vaadin on the class path wouldn't it just default to serving .html anyway?
If you have thymeleaf in ur pom.xml just take it and try have the request mapping return login without defining MVC configuration and see if that works.
Alternatively, use freemarker, not thymeleaf cos thymeleaf is kind of horrible in my opinion and save the file as login.ftl and the contents can just be pure html. Will work perfect without needing to define MVC configuration.

i found out that i can serve html page from static folder same as javascript without having to do any controller . I was trying login because i enabled spring-security and wanted the form login to redirect to login page . the solution was simple loginpage("/login.html") but did not think of it in the first place
http
.authorizeRequests()
.antMatchers("/","/fonts/**","/vendors/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login.html")
.permitAll()
.and()
.logout()
.and()
.csrf().csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(csrfHeaderFilter(), SessionManagementFilter.class);

Related

Spring custom login page only showing in IDE

I am developing a REST-API with Spring Boot. Now I want to act as a OAuth2 provider as well and therefore I want to add support for the "client_credentials" grant type.
In order to do that I have to allow users to login and authorize the client. Spring provides an ugly default login form for doing that so now I want to show my own custom login form instead.
The problem is I can't get it to work outside my IDE.
My configuration looks as follows:
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("**/login")).and().authorizeRequests().antMatchers("/hellopage").hasAuthority(Role.USER.value())
.and().formLogin().defaultSuccessUrl("/hellopage").loginPage("/login").and().logout().permitAll();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/*.css");
web.ignoring().antMatchers("/*.js");
}
}
#Configuration
protected class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/*.js/**").addResourceLocations("/ui/static/");
registry.addResourceHandler("/*.css/**").addResourceLocations("/ui/static/");
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("/login").setViewName("login");
registry.addViewController("/testpage").setViewName("testpage");
registry.addViewController("/hellopage").setViewName("hellopage");
}
#Bean
public InternalResourceViewResolver setupViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/ui/jsp/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
And my folder structure looks like this:
When I run my application inside Eclipse and visit http://localhost:8080/login everything works fine and my custom login form is shown. When I package my application with maven and execute the generated .war file, visiting http://localhost:8080/login shows the ugly default login form which leads me to believe that spring is unable to find the resources for my custom form.
When I try to access any other .jsp like testpage.jsp, I get the following error (this also works fine when the app is run from my IDE):
I am deploying my application using a docker container that runs the .war file using java -jar myserver.war, so this has to work for me.
How can I make sure Spring can find my provided resources when executing the .war file?
By default Maven expects a the jsp's in /WEB-INF/* location.
You can keep the jsp's in src/main/webapp/WEB-INF/jsp. Also you can update the InternalViewResolver prefix as well accordingly.
For detailed explanation you can refer https://stackoverflow.com/a/19786283/3981536

springfox does not return the api doc

I'm trying to integrate springfox in to my existing sprint web application I configured the springfox the web app is starting correctly but the api doc is not getting generated
here is the springfox configuration class
#EnableSwagger2 //Loads the spring beans required by the framework
public class SwaggerConfig {
#Bean
public Docket swaggerSpringMvcPlugin() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo());
}
}
here is the bean creation
<bean id="config" class="com.myApp.general.SwaggerConfig"/>
following is the controller
#Controller
public class MyController {
#ApiOperation(value = "Gets architecture services",
notes = "",
produces = "application/json")
#RequestMapping(value = "v1/users", method = RequestMethod.GET)
#ResponseBody
public Object users(HttpServletResponse response) {
//method implementation
}
}
when i try to get the api doc it just returns a 404. can someone help me on this
it may be a late answer..but should help people still looking/searching
anyway the below answer should work .
for html the ui.html handler is needed
and for others webjars/** is needed
uri.startsWith("/swagger")|| uri.startsWith("/webjars")||uri.startsWith("/v2/api-docs");
if you have filter-chain to access-specific url's ,be sure to omit any filter cheking similar to above code
#Component
public class SwaggerConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}....
adding above code makes your spring application to look into the folders for swagger-ui files.
if you already have a resource handler..donot forget to include these there.In this case no need to write a special resource handler

Spring MVC and WebSockets

I try to add a WebSocket end point to my Spring 4 web app.
I follow this tutorial.
I created and Handler and an Interceptor and I registered them adding this configuration in the file mvc-dispatcher-servlet.xml that is loaded by the
DispatcherServlet .
<bean id="websocket" class="co.syntx.example.websocket.handler.WebsocketEndPoint"/>
<websocket:handlers>
<websocket:mapping path="/websocket" handler="websocket"/>
<websocket:handshake-interceptors>
<bean class="co.syntx.example.websocket.HandshakeInterceptor"/>
</websocket:handshake-interceptors>
</websocket:handlers>
My poblem is that the handler is not registered and I get a 404 error when I try to connect to
ws:localhost:8080/<app-context>/websocket
I also try to user the 'xml-less' configuration (below), but I tried to add a breakpoint in the registerWebSocketHandlers but the method is never invoked.
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
#Configuration
#EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/myHandler");
}
#Bean
public WebSocketHandler myHandler() {
return new MyHandler();
}
}

Serving static web resources in Spring Boot & Spring Security application

I am trying to develop Spring Boot web application and securing it using Spring security java configuration.
After placing my static web resources in 'src/main/resources/public' as advised here in Spring blog, I am able to get the static resources. i.e hitting https://localhost/test.html in browser do serves the html content.
Problem
After I enabled Spring Security, hitting the static resource URL requires authentication.
My relevent Spring Security Java config looks like this:-
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.
authorizeRequests()
.antMatchers("/","/public/**", "/resources/**","/resources/public/**")
.permitAll()
.antMatchers("/google_oauth2_login").anonymous()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/home")
.and()
.csrf().disable()
.logout()
.logoutSuccessUrl("/")
.logoutUrl("/logout") // POST only
.and()
.requiresChannel()
.anyRequest().requiresSecure()
.and()
.addFilterAfter(oAuth2ClientContextFilter(),ExceptionTranslationFilter.class)
.addFilterAfter(googleOAuth2Filter(),OAuth2ClientContextFilter.class)
.userDetailsService(userService);
// #formatter:on
}
How should I configure antMatchers to permit static resources placed inside src/main/resources/public ?
There are a couple of things to be aware of:
The Ant matchers match against the request path and not the path of the resource on the filesystem.
Resources placed in src/main/resources/public will be served from the root of your application.
For example src/main/resources/public/hello.jpg would be served from http://localhost:8080/hello.jpg
This is why your current matcher configuration hasn't permitted access to the static resources. For /resources/** to work, you would have to place the resources in src/main/resources/public/resources and access them at http://localhost:8080/resources/your-resource.
As you're using Spring Boot, you may want to consider using its defaults rather than adding extra configuration. Spring Boot will, by default, permit access to /css/**, /js/**, /images/**, and /**/favicon.ico. You could, for example, have a file named src/main/resources/public/images/hello.jpg and, without adding any extra configuration, it would be accessible at http://localhost:8080/images/hello.jpg without having to log in. You can see this in action in the web method security smoke test where access is permitted to the Bootstrap CSS file without any special configuration.
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**"); // #3
}
Ignore any request that starts with "/resources/". This is similar to configuring http#security=none when using the XML namespace configuration.
This may be an answer (for spring boot 2) and a question at the same time.
It seems that in spring boot 2 combined with spring security everything (means every route/antmatcher) is protected by default if you use an individual security mechanism extended from
WebSecurityConfigurerAdapter
If you don´t use an individual security mechanism, everything is as it was?
In older spring boot versions (1.5 and below) as Andy Wilkinson states in his above answer places like public/** or static/** are permitted by default.
So to sum this question/answer up - if you are using spring boot 2 with spring security and have an individual security mechanism you have to exclusivley permit access to static contents placed on any route. Like so:
#Configuration
public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {
private final ThdAuthenticationProvider thdAuthenticationProvider;
private final ThdAuthenticationDetails thdAuthenticationDetails;
/**
* Overloaded constructor.
* Builds up the needed dependencies.
*
* #param thdAuthenticationProvider a given authentication provider
* #param thdAuthenticationDetails given authentication details
*/
#Autowired
public SpringSecurityConfiguration(#NonNull ThdAuthenticationProvider thdAuthenticationProvider,
#NonNull ThdAuthenticationDetails thdAuthenticationDetails) {
this.thdAuthenticationProvider = thdAuthenticationProvider;
this.thdAuthenticationDetails = thdAuthenticationDetails;
}
/**
* Creates the AuthenticationManager with the given values.
*
* #param auth the AuthenticationManagerBuilder
*/
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(thdAuthenticationProvider);
}
/**
* Configures the http Security.
*
* #param http HttpSecurity
* #throws Exception a given exception
*/
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.antMatchers("/management/**").hasAnyAuthority(Role.Role_Engineer.getValue(),
Role.Role_Admin.getValue())
.antMatchers("/settings/**").hasAnyAuthority(Role.Role_Engineer.getValue(),
Role.Role_Admin.getValue())
.anyRequest()
.fullyAuthenticated()
.and()
.formLogin()
.authenticationDetailsSource(thdAuthenticationDetails)
.loginPage("/login").permitAll()
.defaultSuccessUrl("/bundle/index", true)
.failureUrl("/denied")
.and()
.logout()
.invalidateHttpSession(true)
.logoutSuccessUrl("/login")
.logoutUrl("/logout")
.and()
.exceptionHandling()
.accessDeniedHandler(new CustomAccessDeniedHandler());
}
}
Please mind this line of code, which is new:
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
If you use spring boot 1.5 and below you don´t need to permit these locations (static/public/webjars etc.) explicitly.
Here is the official note, what has changed in the new security framework as to old versions of itself:
Security changes in Spring Boot 2.0 M4
I hope this helps someone.
Thank you!
Have a nice day!
Here is the ultimate solution, after 20+ hours of research.
Step 1. Add 'MvcConfig.java' to your project.
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
}
Step 2. Add configure(WebSecurity web) override to your SecurityConfig class
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
Step 3. Place all static resources in webapp/resources/..
If you are using webjars. You need to add this in your configure method:
http.authorizeRequests().antMatchers("/webjars/**").permitAll();
Make sure this is the first statement. For example:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/webjars/**").permitAll();
http.authorizeRequests().anyRequest().authenticated();
http.formLogin()
.loginPage("/login")
.failureUrl("/login?error")
.usernameParameter("email")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.deleteCookies("remember-me")
.logoutSuccessUrl("/")
.permitAll()
.and()
.rememberMe();
}
You will also need to have this in order to have webjars enabled:
#Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
...
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
...
}
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
String[] resources = new String[]{
"/", "/home","/pictureCheckCode","/include/**",
"/css/**","/icons/**","/images/**","/js/**","/layer/**"
};
http.authorizeRequests()
.antMatchers(resources).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout().logoutUrl("/404")
.permitAll();
super.configure(http);
}
}
i had the same issue with my spring boot application, so I thought it will be nice if i will share with you guys my solution. I just simply configure the antMatchers to be suited to specific type of filles. In my case that was only js filles and js.map. Here is a code:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/index.html", "/", "/home",
"/login","/favicon.ico","/*.js","/*.js.map").permitAll()
.anyRequest().authenticated().and().csrf().disable();
}
}
What is interesting. I find out that resources path like "resources/myStyle.css" in antMatcher didnt work for me at all. If you will have folder inside your resoruces folder just add it in antMatcher like "/myFolder/myFille.js"* and it should work just fine.
In the latest Spring Security 6, the WebSecurityConfigurerAdapter is deprecated.
Declare a WebSecurityCustomizer bean instead.
#Bean
public WebSecurityCustomizer ignoringCustomizer() {
return (web) -> web.ignoring().requestMatchers("...");
}
It,s work for spring security 6.0.*
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeHttpRequests()
.requestMatchers(
"/home/**",
"/login/**",
"/account/starter/**",
"/register/**",
"/plugins/**",
"/dist/**",
"/js/**",
"/**/favicon.ico").permitAll()
.and()
.httpBasic()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
return http.build();
}
"/plugins/**",
"/dist/**",
"/js/**",
... they are located in resources/
plugins, dist, js - these are the names of directories with resources

Configuring spring to return a static file on a Controller method

How do I say to Spring MVC to return a static resource at runtime(in a method)?
Explain better. I configured my application(spring-mvc 3.2.4) to deal with some static resource and to work with two view resolvers, FreeMaker and Json. I wish that in a controller method I would be able to say to spring-mvc that he must take the file in the static resource despite try hadle by one of views resolvers.
My configuration class looks like this:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.xxxx", excludeFilters = #Filter(Configuration.class)})
public class WebConfig extends WebMvcConfigurerAdapter {
...
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/app.js").addResourceLocations("/app.js");
}
...
#Bean
public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {
// Define the view resolvers
List<ViewResolver> resolvers = new ArrayList<ViewResolver>();
JsonViewResolver jsonViewResolver = new JsonViewResolver();
FreeMarkerViewResolver freeMarkerViewResolver = new FreeMarkerViewResolver();
freeMarkerViewResolver.setSuffix("rtl");
resolvers.add(jsonViewResolver);
resolvers.add(freeMarkerViewResolver);
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(manager);
resolver.setViewResolvers(resolvers);
return resolver;
}
}
My controller:
#Controller
#RequestMapping("/")
public class JSViewController {
#RequestMapping(value="*.js")
public String resolveArquivo(HttpServletRequest request){
// Here I would be able to say to sprint to return a static resource instead of hadle it with one of the View Resolvers.
return request.getRequestURI().replace(request.getContextPath(),"");
}
}
Its would be better if you try to access static and dynamic data seperately as hitting a controller for static data will waste your resources, increase latency.
For eg. if you want to access js from jsp then you can use JSTL tag library which would dynamically return the output directory from where you can fetch the static resource.
This gives you the flexibility to cache your static resources (Akamei or something else) or server them from apache instead of tomcat.
If you really want to render your static resource from controller then you need to have an interceptor which could be called before any of the view resolvers which will identify whether the requested resource us static and render accordingly. But this would be invoked for every htttp request which is not desirable.
Unfortunately I wasn't able to figure out how return a static resource in runtime with spring, but I resolved the situation using the old and good Filter.

Resources