Master Spring Security: From Basics to Advanced Customizations
This guide walks through Spring Security fundamentals, including its core authentication and authorization mechanisms, project setup with Maven, customizing usernames, implementing UserDetailsService, creating custom PasswordEncoders, configuring login handling, role and authority checks, CSRF protection, remember‑me functionality, and using security annotations.
Today we present a comprehensive guide to Spring Security, enabling you to fully understand and implement its features.
Spring Security Overview
Spring Security is a highly customizable security framework that leverages Spring IoC/DI and AOP to provide declarative security access control, reducing the amount of repetitive code needed for system security.
Core functions: authentication and authorization.
Authentication Process
Spring Security authentication flow diagram.
Project Setup
Dependency Import
Spring Security is integrated into Spring Boot; simply add the starter dependency.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>Accessing Pages
After adding the starter, Spring Security intercepts all requests by default and redirects unauthenticated users to the built‑in login page.
In a browser visit http://localhost:8080/ to see the login page.
Default username: user. Password is printed to the console on application start.
Custom Username and Password
Edit application.yml to define static users.
# Static user, typically used in internal network authentication
spring:
security:
user:
name: test # static username
password: test # static passwordUserDetailsService Details
When no configuration is provided, Spring Security generates default credentials. In real projects, credentials are fetched from a database, so you need to implement UserDetailsService to customize authentication logic.
@Component
public class UserSecurity implements UserDetailsService {
@Autowired
private UserService userService;
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
User user = userService.login(userName);
if (null == user) {
throw new UsernameNotFoundException("用户名错误");
}
return new org.springframework.security.core.userdetails.User(
userName, user.getPassword(),
AuthorityUtils.createAuthorityList()
);
}
}PasswordEncoder Details
PasswordEncoder
The PasswordEncoder interface handles password hashing and verification. Spring Security provides several implementations.
Custom PasswordEncoder
Implement the PasswordEncoder interface.
/**
* Credential matcher for authentication.
* Core methods:
* 1. encode – hash plain password.
* 2. matches – verify plain vs hashed password.
*/
public class MyMD5PasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence charSequence) {
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
return toHexString(digest.digest(charSequence.toString().getBytes()));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return "";
}
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(encode(charSequence));
}
private String toHexString(byte[] tmp) {
StringBuilder builder = new StringBuilder();
for (byte b : tmp) {
String s = Integer.toHexString(b & 0xFF);
if (s.length() == 1) {
builder.append("0");
}
builder.append(s);
}
return builder.toString();
}
}Register the encoder in a configuration class:
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // built‑in implementation
}Login Configuration
Method 1 – Forward
http.formLogin()
.usernameParameter("name")
.passwordParameter("pswd")
.loginPage("/toLogin")
.loginProcessingUrl("/login")
.failureForwardUrl("/failure")
.successForwardUrl("/toMain");Method 2 – Redirect
http.formLogin()
.usernameParameter("name")
.passwordParameter("pswd")
.loginPage("/toLogin")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/toMain", true)
.failureUrl("/failure");Custom Handlers
Define custom authentication failure and success handlers by implementing AuthenticationFailureHandler and AuthenticationSuccessHandler.
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
private String url;
private boolean isRedirect;
// constructor, getters, setters omitted
@Override
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException e) throws IOException, ServletException {
if (isRedirect) {
response.sendRedirect(url);
} else {
request.getRequestDispatcher(url).forward(request, response);
}
}
}Security Configuration Class
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserSecurity userSecurity;
@Autowired
private PersistentTokenRepository persistentTokenRepository;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginPage("/toLogin")
.usernameParameter("name")
.passwordParameter("pswd")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/toMain")
.failureUrl("/toLogin");
http.authorizeRequests()
.antMatchers("/toLogin", "/register", "/login", "/favicon.ico").permitAll()
.antMatchers("/**/*.js").permitAll()
.regexMatchers(".*[.]css").permitAll()
.anyRequest().authenticated();
http.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutSuccessUrl("/")
.logoutUrl("/logout");
http.csrf().disable();
}
@Bean
public PersistentTokenRepository persistentTokenRepository(DataSource dataSource) {
JdbcTokenRepositoryImpl repo = new JdbcTokenRepositoryImpl();
repo.setDataSource(dataSource);
return repo;
}
}Role and Authority
hasAuthority(String) – checks if the current user has a specific authority.
http.authorizeRequests().antMatchers("/main1.html").hasAuthority("admin");hasAnyAuthority(String…) – allows access if the user has any of the listed authorities.
http.authorizeRequests().antMatchers("/admin/read").hasAnyAuthority("xxx","xxx");hasRole(String) – requires the user to have a given role (role name must be prefixed with ROLE_ ).
http.authorizeRequests().antMatchers("/admin/read").hasRole("管理员");hasAnyRole(String…) – allows access if the user has any of the specified roles.
http.authorizeRequests().antMatchers("/guest/read").hasAnyRole("管理员","访客");hasIpAddress(String) – restricts access to requests from a particular IP address.
http.authorizeRequests().antMatchers("/ip").hasIpAddress("127.0.0.1");403 Access‑Denied Handling
Implement AccessDeniedHandler to return a custom HTML response when a user lacks sufficient permissions.
@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException e) throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(
"<html><body><div style='width:800px;text-align:center;margin:auto;font-size:24px'>"
+ "权限不足,请联系管理员"
+ "</div></body></html>"
);
response.getWriter().flush();
}
}Configure it via
http.exceptionHandling().accessDeniedHandler(myAccessDeniedHandler).
Remember‑Me
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.rememberMe()
.rememberMeParameter("remember-me")
.tokenValiditySeconds(14 * 24 * 60 * 60)
.rememberMeCookieName("remember-me")
.tokenRepository(persistentTokenRepository)
.userDetailsService(userSecurity);
}
}Spring Security Annotations
@Secured
Restricts method access to users with specified roles (roles must be prefixed with ROLE_).
@Secured({"ROLE_管理员","ROLE_访客"})
@RequestMapping("/toMain")
public String toMain() {
return "main";
}Enable with @EnableGlobalMethodSecurity(securedEnabled = true).
@PreAuthorize
Evaluates an expression before method execution to enforce permissions.
@PreAuthorize("hasAnyRole('ROLE_管理员','ROLE_访客')")
@RequestMapping("/toMain")
public String toMain() {
return "main";
}Enable with @EnableGlobalMethodSecurity(prePostEnabled = true).
@PostAuthorize
Evaluates an expression after method execution.
@PostAuthorize("hasRole('ROLE_管理员')")
@RequestMapping("/toMain")
public String toMain() {
return "main";
}CSRF
Cross‑Site Request Forgery (CSRF) is an attack where a malicious site tricks a user's browser into sending unintended requests to a trusted site, exploiting the fact that browsers automatically include cookies such as the session ID.
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.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
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.
