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.

Programmer DD
Programmer DD
Programmer DD
Master Spring Security: From Basics to Advanced Customizations

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 password

UserDetailsService 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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaAuthenticationCSRFAuthorizationspring-securityPasswordEncoder
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.