Implementing Spring Security 5 with Spring MVC: Configuration and Custom Authentication Flow

Core Dependencies

Include the foundational artifacts required for secure endpoint protection within a Spring MVC architecture.

<properties>
    <spring.security.version>5.0.5.RELEASE</spring.security.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>${spring.security.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
        <version>${spring.security.version}</version>
    </dependency>
</dependencies>

Servlet Container Initialization

The web container must instantiate the security filter chain prior to processing standard request mappings. Configure the deployment descriptor to route traffic through a Spring-managed proxy.

<filter>
    <filter-name>applicationSecurityFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
        <param-name>targetBeanName</param-name>
        <param-value>springSecurityFilterChain</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>applicationSecurityFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Register listeners and servlet definitions sequentially after the filter mapping -->

Custom User Detail Service

Spring Security expects a component that implements UserDetailsService to resolve credentials during the authentication handshake. The resulting UserDetails instance carries the username, encoded password, account status flags, and a list of granted authorities.

Authorization checks evaluate GrantedAuthority strings directly. Framework evaluators like hasRole('ADMIN') automatically prepend ROLE_ internally. Consequently, domain models must append this prefix when constructing authority collections, even if the persistence layer stores unprefixed identifiers.

@Service("userAuthProvider")
public class ApplicationUserProvider implements UserDetailsService {

    @Autowired 
    private AppUserRepository appUserRepository;

    @Override
    public UserDetails loadUserByUsername(String loginIdentifier) throws UsernameNotFoundException {
        Optional<AppUser> userOpt = appUserRepository.findByLoginName(loginIdentifier);
        
        return userOpt.map(user -> {
            List<SimpleGrantedAuthority> authorityList = assemblePrivileges(user.getAssignedRoles());
            return new org.springframework.security.core.userdetails.User(
                user.getLoginName(),
                user.getPasswordDigest(),
                true,   // enabled
                true,   // account non-expired
                true,   // credentials non-expired
                true,   // account non-locked
                authorityList
            );
        }).orElseThrow(() -> new UsernameNotFoundException("Credential verification failed"));
    }

    private List<SimpleGrantedAuthority> assemblePrivileges(Set<RoleEntity> roles) {
        return roles.stream()
            .flatMap(this::extractRoleAndTokenPairs)
            .collect(Collectors.toList());
    }

    private Stream<String> extractRoleAndTokenPairs(RoleEntity role) {
        String securedRole = "ROLE_" + role.getCode().toUpperCase();
        List<String> rights = new ArrayList<>();
        rights.add(securedRole);
        role.getAppPermissions().forEach(pt -> rights.add(pt.getTokenKey()));
        return rights.stream().map(SimpleGrantedAuthority::new);
    }
}

Declarative Security Policy

XML-based policies define interception rules, session handling, and credential verification pipelines. Attach this configuration to the primary application context.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/security
                           http://www.springframework.org/schema/security/spring-security.xsd">

    <!-- Public asset directories skip authentication -->
    <security:http pattern="/static/**" security="none"/>
    <security:http pattern="/templates/**" security="none"/>
    
    <!-- Request filtering rules -->
    <security:http use-expressions="true">
        <security:headers>
            <security:frame-options policy="SAMEORIGIN"/>
        </security:headers>

        <security:intercept-url pattern="/portal/**" access="isAuthenticated()"/>
        <security:intercept-url pattern="/admin/**" access="hasAuthority('ADMIN_PANEL')"/>

        <security:form-login 
            login-page="/gateway.html"
            username-parameter="accessId"
            password-parameter="secretKey"
            login-processing-url="/process-auth"
            default-target-url="/dashboard"
            authentication-failure-url="/gateway.html?fail=1"/>

        <security:logout 
            logout-url="/terminate-session" 
            logout-success-url="/gateway.html" 
            invalidate-session="true"/>

        <security:csrf disabled="true"/>
    </security:http>

    <!-- Cryptographic hasher -->
    <bean id="credentialHasher" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>

    <!-- Verification orchestrator -->
    <security:authentication-manager>
        <security:authentication-provider user-service-ref="userAuthProvider">
            <security:password-encoder ref="credentialHasher"/>
        </security:authentication-provider>
    </security:authentication-manager>

    <!-- Activate annotation-driven enforcement -->
    <security:global-method-security pre-post-annotations="enabled"/>
</beans>

Merge the policy definition in to the MVC context:

<import resource="classpath:security-deployment.xml"/>

Programmatic Method Guarding

Apply restrictions directly onto bussiness logic methods. The framework evaluates the expression against the active security context upon invocation.

@RestController
@RequestMapping("/config")
public class SystemSettingsController {

    @PreAuthorize("hasAuthority('PARAMETER_MODIFY')")
    @PutMapping("/update")
    public StatusResponse applyConfiguration(SettingsPayload dto) {
        // Execution guarded by declared privileges
        return new StatusResponse(true);
    }
}

Active Principle Resolution

Extract identity data during service execution. Verify the presence of an authenticated token before casting the principal object.

public String identifyActiveOperator() {
    Authentication currentAuth = SecurityContextHolder.getContext().getAuthentication();
    
    if (currentAuth != null && currentAuth.isAuthenticated()) {
        Object subject = currentAuth.getPrincipal();
        if (subject instanceof org.springframework.security.core.userdetails.User) {
            return ((org.springframework.security.core.userdetails.User) subject).getUsername();
        }
    }
    throw new SecurityException("Execution requires verified credentials");
}

Tags: spring-security spring-mvc java Authentication Authorization

Posted on Sat, 17 Oct 2026 16:16:07 +0000 by deljhp