Master Spring Security: Custom Request Interception & Login Page
This tutorial demonstrates how to configure Spring Security to selectively intercept requests, permit static resources, enforce role‑based access, and replace the default login page with a custom Thymeleaf view, complete with code examples and screenshots.
Custom Request Interception
By default, Spring Security intercepts every request, including static resources, which is often undesirable. First, create a static resource directory and configure Spring Boot to serve it under a custom prefix.
spring:
mvc:
static-path-pattern: /resources/**After adding Spring Security back to the project, requests to /resources/** will be redirected to the login page unless explicitly permitted.
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/resources/**")
.permitAll();
http.formLogin();
}
}To allow static resources while protecting all other endpoints, place the antMatchers rule before the anyRequest rule:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/resources/**")
.permitAll();
http.authorizeRequests()
.anyRequest()
.authenticated();
http.formLogin();
}Reversing the order triggers the following exception:
Caused by: java.lang.IllegalStateException: Can't configure antMatchers after anyRequest
at org.springframework.util.Assert.state(Assert.java:76) ~[spring-core-5.3.12.jar:5.3.12]Define two sample controllers:
@RestController
@RequestMapping("/demos")
public class DemoController {
@GetMapping("home")
public Object home() { return "demos home"; }
}
@RestController
@RequestMapping("/api")
public class ApiController {
@GetMapping("/{id}")
public Object get(@PathVariable("id") Integer id) {
return "获取 - " + id + " - 数据";
}
}Configure role‑based access so that /demos/** requires the USERS role and /api/** requires the ADMIN role:
http.authorizeRequests().antMatchers("/demos/**").hasRole("USERS");
http.authorizeRequests().antMatchers("/api/**").hasRole("ADMIN");
http.authorizeRequests().anyRequest().authenticated();
http.formLogin();Define in‑memory users for testing:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.passwordEncoder(NoOpPasswordEncoder.getInstance())
.withUser("guest").password("123456").roles("ADMIN")
.and()
.withUser("test").password("666666").roles("USERS");
}Use hasAnyRole to grant access when a user possesses any one of several roles:
http.authorizeRequests().antMatchers("/demos/**").hasAnyRole("USERS","AKKF","BLLE");
http.authorizeRequests().antMatchers("/api/**").hasAnyRole("ADMIN","MGR","SYSTEM");Other useful configurations include assigning the same authority to multiple URIs and controlling access by HTTP method:
http.authorizeRequests().antMatchers("/demos/**","/api/**").hasAnyAuthority("ROLE_USERS","ROLE_ADMIN");
http.authorizeRequests().antMatchers(HttpMethod.GET).permitAll();Custom Login Page
Add Thymeleaf dependencies to the project:
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>Configure Thymeleaf template location:
spring:
thymeleaf:
prefix: classpath:/templates/Create login.html under src/main/resources/templates/. The essential markup includes a form that posts to /login and displays error messages when authentication fails.
<div class="loginContainer">
<div class="pageTitle"><h3>认证登录</h3></div>
<div class="loginPanel">
<div class="loginTitle">安全登录</div>
<div class="loginContent">
<form method="post" action="login">
<div class="c-row">
<label>安全帐号</label>
<input type="text" name="username" placeholder="帐号" />
</div>
<div class="c-row">
<label>安全密码</label>
<input type="password" name="password" placeholder="密码" />
</div>
<div class="c-row">
<input type="checkbox" name="remember-me" /><label for="remember-me">记住我</label>
</div>
<div class="c-row" style="margin-top:20px;">
<button type="submit" class="btn btn-sm btn-primary">安全登录</button>
</div>
</form>
<div th:if="${param.error}" class="alert alert-danger">[[${session.SPRING_SECURITY_LAST_EXCEPTION?.message}]]</div>
</div>
</div>
</div>Map the custom login page with a controller:
@Controller
public class LoginController {
@GetMapping("/custom/login")
public String login() { return "login"; }
}Finally, tell Spring Security to use this page:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests().antMatchers("/resources/**").permitAll();
http.authorizeRequests().antMatchers("/demos/**").hasRole("USERS");
http.authorizeRequests().antMatchers("/api/**").hasRole("ADMIN");
http.formLogin().loginPage("/custom/login");
}Summary :
How to configure Spring Security to intercept requests and permit static resources.
How to enforce role‑based access for specific URI patterns.
How to replace the default login page with a custom Thymeleaf view.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
