I defined the SecurityFilterChain bean like below
@Bean
public SecurityFilterChain securityFilterChain (HttpSecurity http) throws Exception {
// We are disabling CSRF so that our forms don't complain about a CSRF token.
// Beware that it can create a security vulnerability
return http.csrf(AbstractHttpConfigurer::disable)
// Here we are configuring our login form
// .formLogin(Customizer.withDefaults())
.formLogin(formLogin -> {
formLogin
.loginPage("/login") // Login page will be accessed through this endpoint. We will create a controller method for this.
.loginProcessingUrl("/login-processing") // This endpoint will be mapped internally. This URL will be our Login form post action.
.usernameParameter("username")
.passwordParameter("password")
.permitAll() // We re permitting all for login page
.defaultSuccessUrl("/") // If the login is successful, user will be redirected to this URL.
.failureUrl("/login?error=true"); // If the user fails to login, application will redirect the user to this endpoint
}
)
.authorizeHttpRequests(authorize ->
authorize
// We are permitting all static resources to be accessed publicly
.requestMatchers("/images/**", "/css/**", "/js/**").permitAll()
// We are restricting endpoints for individual roles.
// Only users with allowed roles will be able to access individual endpoints.
.requestMatchers("/course/add").hasRole("ADMIN")
.requestMatchers("/course/show-all").hasAnyRole("ADMIN", "USER")
.requestMatchers("/course/edit").hasAnyRole("USER")
// Following line denotes that all requests must be authenticated.
// Hence, once a request comes to our application, we will check if the user is authenticated or not.
.anyRequest().authenticated()
)
.logout(logout ->
logout
.logoutUrl("/logout")
.logoutSuccessUrl("/")
)
.build();
}
Unfortunately, this code does not work for custom form login, but works perfectly for form login with default configuration (which is also commented in the code),
Comment From: mainul35
As a result, I am getting the following page.
Comment From: marcusdacoregio
Hi @mainul35,
can you provide more details about the configuration, like the related code for the custom login page, the /login-processing endpoint etc?
Comment From: mainul35
Hello @marcusdacoregio, Here is my login controller endpoint
@Controller
@RequestMapping("/")
public class RootController {
@GetMapping("/login")
public String login(Model model, @RequestParam(name="error", required = false) String error) {
model.addAttribute("error", error);
return "auth/login";
}
}
- WebMvcConfigurer implementation class
@EnableWebMvc
@Configuration
@ComponentScan(basePackages = { "com.spring5.practice.controllers" })
public class ServletConfig implements WebMvcConfigurer {
// Configuration to render VIEWS
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/views/", ".jsp");
}
// Configuration to render STATIC CONTENTS (IMAGE, CSS, JS)
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// Register resource handler for -
// IMAGES
registry.addResourceHandler("/images/**").addResourceLocations("/WEB-INF/resources/images/");
// CSS
registry.addResourceHandler("/css/**").addResourceLocations("/WEB-INF/resources/css/");
// JAVASCRIPT
registry.addResourceHandler("/js/**").addResourceLocations("/WEB-INF/resources/js/");
}
}
-
Login page location
-
Login page contents
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Login</title>
<link rel="stylesheet"
href="${pageContext.request.contextPath }/css/bootstrap.min.css">
<link rel="stylesheet"
href="${pageContext.request.contextPath }/css/login.css">
<script type="text/javascript"
src="${pageContext.request.contextPath }/js/bootstrap.min.js"></script>
<script type="text/javascript"
src="${pageContext.request.contextPath }/js/jquery.js"></script>
</head>
<body>
<c:if test="${error == 'true'}">
<div class="alert alert-danger" role="alert">Wrong username or
password
</div>
</c:if>
<div class="sidenav">
<div class="login-main-text">
<h2>
Application<br> Login Page
</h2>
<p>Login or register from here to access.</p>
</div>
</div>
<div class="main">
<div class="col-md-6 col-sm-12">
<div class="login-form">
<form action="${pageContext.request.contextPath }/login-processing"
method="POST">
<div class="form-group">
<label>User Name</label> <input type="text" name="username"
class="form-control" placeholder="User Name">
</div>
<div class="form-group">
<label>Password</label> <input type="password"
class="form-control" name="password" placeholder="Password">
</div>
<button type="submit" class="btn btn-black">Login</button>
<button type="submit" class="btn btn-secondary">Register</button>
</form>
</div>
</div>
</div>
</body>
</html>
Please let me know, if you need more information.
Comment From: marcusdacoregio
Can you confirm if it works with Spring Security < 6? It would be nice if you can enable TRACE logs for org.springframework.security and analyze the output.
In addition to that, can you try:
http
.securityContext(context -> context
.requireExplicitSave(false)
)
// ...
Comment From: mainul35
Hello @marcusdacoregio , this project was in Spring 5.2.11 before. I am migrating to Spring 6.x for updating my articles. It was working perfectly. Moreover, just after the release of Spring 6.0, I migrated one of my projects to Spring 6 from Spring 5, and it perfectly works. Here is that project security configuration file link that is currently in Spring 6.0 migrated from 5.x
https://github.com/mainul35/University-QA-Board/blob/migrated/Spring-6.x/src/main/java/com/mainul35/config/security/SecurityConfig.java
- I will enable TRACE log and let you know the logs ASAP.
- I just tried the suggeded configuration that you just commented above. It didn't work.
Comment From: mainul35
Hello @marcusdacoregio , after enabling the TRACE log for Spring Security, I found the following line in the log.
So I set the authorization of my view page location, "/WEB-INF/views/**" in my case to permitAll()
authorize
// We are permitting all static resources to be accessed publicly
.requestMatchers("/images/**", "/css/**", "/js/**", "/WEB-INF/views/**").permitAll()
// We are restricting endpoints for individual roles.
// Only users with allowed roles will be able to access individual endpoints.
.requestMatchers("/course/add").hasRole("ADMIN")
.requestMatchers("/course/show-all").hasAnyRole("ADMIN", "USER")
.requestMatchers("/course/edit").hasAnyRole("USER")
// Following line denotes that all requests must be authenticated.
// Hence, once a request comes to our application, we will check if the user is authenticated or not.
.anyRequest().authenticated()
And it worked like a charm!
Thank you for your kind support :)
Comment From: christ774
Good afternoon, I've been trying to solve this error for a long time and I haven't been able to. following your pos it is no longer possible to redirect to a custom login in the latest version of spring
My view is made in html, css and javascript and I also have some images, can you please tell me how I can do it? I also want to ask you if it is more convenient to make a controller, the front connects to it and from there login, it is instead of redirecting the spring security login.
I thank you very much
} /*@Override public void addViewControllers(ViewControllerRegistry viewControllerRegistry){ viewControllerRegistry.addViewController("/login").setViewName("login.html");
}*/
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf(AbstractHttpConfigurer::disable)// lo desactive por que no me deja trabajar en postman
.authorizeRequests(authorize -> authorize
.requestMatchers("/admin", "/admin/save", "/contenido/save").permitAll()
.requestMatchers("src/main/resources/templates").permitAll()
.anyRequest().authenticated()
)
.formLogin(formLogin-> formLogin
.loginPage("/login")
.permitAll()
);
@Controller public class ControllerLogin {
@RequestMapping(value="/login", method= RequestMethod.GET)
public String login() {
return "redirect:/login.html";
}
This page isn’t workinglocalhost redirected you too many times. Try clearing your cookies. ERR_TOO_MANY_REDIRECTS
}
Comment From: mainul35
First of all, set /WEB-INF/views/** to permit all, like the code below in your spring security http configuration
requestMatchers("/images/**", "/css/**", "/js/**", "/WEB-INF/views/**").permitAll()
Next, in your controller method, return should be only your view name. Replace return "redirect:/login.html"; to return "login";
If your view page is in the correct location, it should work.
Comment From: abhisable
It's not working when we are using below code with mvc.pattern , which is required in latest version. Any suggestions what could be resolution? @Bean public SecurityFilterChain settingUpSecurityFilterChain() throws Exception {
httpSecurity.authorizeHttpRequests(customizer->{
customizer.requestMatchers(mvc.pattern("/hello"),mvc.pattern("/helloworld"))
.authenticated();
customizer.requestMatchers(mvc.pattern("/bye")).permitAll();
customizer.requestMatchers(mvc.pattern("/WEB-INF/views/**")).permitAll();
});
httpSecurity.formLogin(formLoginCustomizer->{
formLoginCustomizer.loginPage("/myCustomLogin");
});
// httpSecurity.formLogin(Customizer.withDefaults()); httpSecurity.httpBasic(Customizer.withDefaults());
return httpSecurity.build();
}
Comment From: sudheerUzumaki
The configuration httpSecurity.formLogin(formLoginCustomizer -> formLoginCustomizer.loginPage("/myCustomLogin")); instructs Spring Security to redirect unauthorized requests to /myCustomLogin.
To understand why localhost is redirecting excessively, consider this: when an unauthorized request occurs, Spring Security redirects to the login page URL. If this URL requires authentication, it creates a redirect loop back to itself, resulting in the 'localhost redirected too many times' error.
Solution:
The solution is to set up HttpSecurity for form login like so: httpSecurity.formLogin(f -> f.loginPage("/loginpage").permitAll());.
If the login page URL is not the URL for the actual page causing the redirection, you should allow "/page.html" without authentication in the request matchers.
HttpSecurity.authorizeHttpRequests(customizer -> customizer.requestMatchers("/page.html").permitAll());
Comment From: SuleymanCommits
The configuration
httpSecurity.formLogin(formLoginCustomizer -> formLoginCustomizer.loginPage("/myCustomLogin"));instructs Spring Security to redirect unauthorized requests to/myCustomLogin.To understand why localhost is redirecting excessively, consider this: when an unauthorized request occurs, Spring Security redirects to the login page URL. If this URL requires authentication, it creates a redirect loop back to itself, resulting in the 'localhost redirected too many times' error.
Solution: The solution is to set up HttpSecurity for form login like so:
httpSecurity.formLogin(f -> f.loginPage("/loginpage").permitAll());.If the login page URL is not the URL for the actual page causing the redirection, you should allow "/page.html" without authentication in the request matchers.
HttpSecurity.authorizeHttpRequests(customizer -> customizer.requestMatchers("/page.html").permitAll());
I've configured form login like that but still experiencing a redirect loop.
.formLogin(form -> form.loginPage("/login").permitAll())
Comment From: sudheerUzumaki
The configuration
httpSecurity.formLogin(formLoginCustomizer -> formLoginCustomizer.loginPage("/myCustomLogin"));instructs Spring Security to redirect unauthorized requests to/myCustomLogin. To understand why localhost is redirecting excessively, consider this: when an unauthorized request occurs, Spring Security redirects to the login page URL. If this URL requires authentication, it creates a redirect loop back to itself, resulting in the 'localhost redirected too many times' error. Solution: The solution is to set up HttpSecurity for form login like so:httpSecurity.formLogin(f -> f.loginPage("/loginpage").permitAll());. If the login page URL is not the URL for the actual page causing the redirection, you should allow "/page.html" without authentication in the request matchers. HttpSecurity.authorizeHttpRequests(customizer -> customizer.requestMatchers("/page.html").permitAll());I've configured form login like that but still experiencing a redirect loop.
.formLogin(form -> form.loginPage("/login").permitAll())
login is not the page,it returns the page,instead it should be login.jsp or login.html or you can allow it : http..authorizeHttpRequests((authorize) -> authorize .requestMatchers("/login.extension") .permitAll().anyRequest().authenticated())
Comment From: SuleymanCommits
The configuration
httpSecurity.formLogin(formLoginCustomizer -> formLoginCustomizer.loginPage("/myCustomLogin"));instructs Spring Security to redirect unauthorized requests to/myCustomLogin. To understand why localhost is redirecting excessively, consider this: when an unauthorized request occurs, Spring Security redirects to the login page URL. If this URL requires authentication, it creates a redirect loop back to itself, resulting in the 'localhost redirected too many times' error. Solution: The solution is to set up HttpSecurity for form login like so:httpSecurity.formLogin(f -> f.loginPage("/loginpage").permitAll());. If the login page URL is not the URL for the actual page causing the redirection, you should allow "/page.html" without authentication in the request matchers. HttpSecurity.authorizeHttpRequests(customizer -> customizer.requestMatchers("/page.html").permitAll());I've configured form login like that but still experiencing a redirect loop.
.formLogin(form -> form.loginPage("/login").permitAll())login is not the page,it returns the page,instead it should be login.jsp or login.html or you can allow it : http..authorizeHttpRequests((authorize) -> authorize .requestMatchers("/login.extension") .permitAll().anyRequest().authenticated())
doesn't matter, /login is a controller that returns "login" or login.html
Comment From: sudheerUzumaki
The configuration
httpSecurity.formLogin(formLoginCustomizer -> formLoginCustomizer.loginPage("/myCustomLogin"));instructs Spring Security to redirect unauthorized requests to/myCustomLogin. To understand why localhost is redirecting excessively, consider this: when an unauthorized request occurs, Spring Security redirects to the login page URL. If this URL requires authentication, it creates a redirect loop back to itself, resulting in the 'localhost redirected too many times' error. Solution: The solution is to set up HttpSecurity for form login like so:httpSecurity.formLogin(f -> f.loginPage("/loginpage").permitAll());. If the login page URL is not the URL for the actual page causing the redirection, you should allow "/page.html" without authentication in the request matchers. HttpSecurity.authorizeHttpRequests(customizer -> customizer.requestMatchers("/page.html").permitAll());I've configured form login like that but still experiencing a redirect loop.
.formLogin(form -> form.loginPage("/login").permitAll())login is not the page,it returns the page,instead it should be login.jsp or login.html or you can allow it : http..authorizeHttpRequests((authorize) -> authorize .requestMatchers("/login.extension") .permitAll().anyRequest().authenticated())
doesn't matter, /login is a controller that returns "login" or login.html
yes,you are allowing login end point without authentication,but not login.html ,you can also allow it without authentication by : http..authorizeHttpRequests((authorize) -> authorize .requestMatchers("/login.html") .permitAll().anyRequest().authenticated())
Comment From: SuleymanCommits
The configuration
httpSecurity.formLogin(formLoginCustomizer -> formLoginCustomizer.loginPage("/myCustomLogin"));instructs Spring Security to redirect unauthorized requests to/myCustomLogin. To understand why localhost is redirecting excessively, consider this: when an unauthorized request occurs, Spring Security redirects to the login page URL. If this URL requires authentication, it creates a redirect loop back to itself, resulting in the 'localhost redirected too many times' error. Solution: The solution is to set up HttpSecurity for form login like so:httpSecurity.formLogin(f -> f.loginPage("/loginpage").permitAll());. If the login page URL is not the URL for the actual page causing the redirection, you should allow "/page.html" without authentication in the request matchers. HttpSecurity.authorizeHttpRequests(customizer -> customizer.requestMatchers("/page.html").permitAll());I've configured form login like that but still experiencing a redirect loop.
.formLogin(form -> form.loginPage("/login").permitAll())login is not the page,it returns the page,instead it should be login.jsp or login.html or you can allow it : http..authorizeHttpRequests((authorize) -> authorize .requestMatchers("/login.extension") .permitAll().anyRequest().authenticated())
doesn't matter, /login is a controller that returns "login" or login.html
yes,you are allowing login end point without authentication,but not login.html ,you can also allow it without authentication by : http..authorizeHttpRequests((authorize) -> authorize .requestMatchers("/login.html") .permitAll().anyRequest().authenticated())
Securing GET /login
2024-08-12T13:11:23.906+04:00 DEBUG 127703 --- [nio-8080-exec-1] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
2024-08-12T13:11:23.915+04:00 DEBUG 127703 --- [nio-8080-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor : Authorized filter invocation [GET /login] with attributes [permitAll]
2024-08-12T13:11:23.916+04:00 DEBUG 127703 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Secured GET /login
2024-08-12T13:11:23.949+04:00 DEBUG 127703 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Securing GET /error
2024-08-12T13:11:23.950+04:00 WARN 127703 --- [nio-8080-exec-1] o.s.w.s.h.HandlerMappingIntrospector : Cache miss for ERROR dispatch to '/error' (previous null). Performing MatchableHandlerMapping lookup. This is logged once only at WARN level, and every time at TRACE.
2024-08-12T13:11:23.958+04:00 DEBUG 127703 --- [nio-8080-exec-1] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
2024-08-12T13:11:23.959+04:00 DEBUG 127703 --- [nio-8080-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor : Authorized filter invocation [GET /error] with attributes [permitAll]
2024-08-12T13:11:23.959+04:00 DEBUG 127703 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Secured GET /error
I don't know why it's redirecting to /error, I've permitted both /login and /login.html and also did
.formLogin(form -> form.loginPage("/login").permitAll())
EDIT: Apparently it's because I was visiting the wrong link. My controller class was annotated with @RequestMapping("/user") and then the controller method was annotated with GetMapping("/login) but I was visiting localhost:8080/login instead of localhost:8080/user/login which is why it kept redirecting me to error page. Thanks for the heads up about allowing login.html by the way @sudheerUzumaki
Comment From: wizzy-abhishek
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable) // Disable CSRF for simplicity, enable in production with proper configuration
.authorizeHttpRequests(authorize -> authorize
.requestMatchers(HttpMethod.GET, "/api/resource").permitAll() // Allow GET requests to /api/resource
.requestMatchers(HttpMethod.POST, "/api/resource").hasRole("ADMIN") // Allow POST requests to /api/resource for users with USER role
.requestMatchers(HttpMethod.PUT, "/api/resource").hasRole("ADMIN") // Allow PUT requests to /api/resource for users with ADMIN role
.requestMatchers(HttpMethod.DELETE, "/api/resource").hasRole("ADMIN") // Allow TO DELETE requests to /api/resource for users with ADMIN role
.anyRequest().authenticated()) // All other requests need to be authenticated
.formLogin(form ->
form
.loginPage("/login")
.permitAll()
)
.httpBasic(Customizer.withDefaults());
return http.build();
}
<!DOCTYPE html>
Hospital Name
Your expertise , enhanced by our technology
Its a .jsp page
spring.mvc.view.suffix=.jsp
spring.mvc.view.prefix=/views/
I am stuck kindly help
Comment From: sudheerUzumaki
you should allow "/views/login.jsp" without authentication in the request matchers.
Comment From: koisurunippon
Thanks so much, I had the same problem and your solution above saved me.
Comment From: ranjit485
.requestMatchers("/static/", "/css/", "/js/", "/images/","/WEB-INF/views/**").permitAll() This worked for me