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");
}