Skip to the content.

🧠 Authorization with Spring Security (Spring 5.3.x + Jakarta EE 8, Legacy WAR)

Audience: Intermediate-to-Advanced Java Developers
Duration: ~3 hours (Lecture + Hands-on exercises)
Stack:


🎯 Learning Objectives

By the end of this session, participants will:

  1. Apply URL-based and method-level security using Spring Security.
  2. Use @PreAuthorize, @Secured, and JSP <sec:authorize> tags for role checks.
  3. Customize security logic using expressions and AccessDecisionVoters.
  4. Configure a database-backed UserDetailsService.
  5. Implement fine-grained object-level authorization with ACLs.

🧭 1. Introduction

Goals:

Talking Points:

Spring Security integrates into servlet-based Jakarta EE apps using manual filter registration and beans. You don’t need Spring Boot to build secure enterprise apps. In this project, we manage Registration entities, secured for admin-only operations like deletion.


🔐 2. Checking Authorization Rules in Code

Topics:

Hands-On:

Modify the deleteRegistration() method in DefaultRegistrationService:

public void deleteRegistration(long registrationId) {
    if (SecurityContextHolder.getContext().getAuthentication()
            .getAuthorities().stream()
            .anyMatch(auth -> auth.getAuthority().equals("ROLE_ADMIN"))) {
        if (registrationRepositoryJPA.existsById(registrationId)) {
            registrationRepositoryJPA.remove(registrationId);
        } else {
            throw new IllegalArgumentException("Registration with ID " + registrationId + " not found");
        }
    } else {
        throw new AccessDeniedException("Not an admin");
    }
}

🧱 3. Declaring URL and Method Security

Use actual SecurityConfig:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .antMatchers("/login", "/resources/**").permitAll()
            .antMatchers("/chat", "/registration/**").authenticated()
            .antMatchers("/registration/delete/**").hasRole("ADMIN")
            .anyRequest().authenticated()
        .and()
        .formLogin().loginPage("/login").defaultSuccessUrl("/registration/list")
        .and()
        .logout().logoutUrl("/logout").logoutSuccessUrl("/login?logout")
        .and()
        .csrf().disable();
    return http.build();
}

Hands-On:


🏷 4. Using Spring Security Annotations

Concepts:

Enable annotations:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig {
    // Existing configuration
}

JSP Tags:

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<sec:authorize access="hasRole('ADMIN')">
    <form action="/registration/delete/${registration.id}" method="post">
        <button type="submit">Delete</button>
    </form>
</sec:authorize>

Hands-On:


🧠 5. Understanding Authorization Decisions (30 minutes)

Concepts:

Example: Business hours voter

public class BusinessHoursVoter implements AccessDecisionVoter<Object> {
    public int vote(Authentication auth, Object object, Collection<ConfigAttribute> attrs) {
        LocalTime now = LocalTime.now();
        return (now.isAfter(LocalTime.of(9, 0)) && now.isBefore(LocalTime.of(17, 0)))
            ? ACCESS_GRANTED : ACCESS_DENIED;
    }
}

Register:

<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
    <constructor-arg>
        <list>
            <bean class="org.springframework.security.access.vote.RoleVoter" />
            <bean class="com.nicordesigns.security.BusinessHoursVoter" />
        </list>
    </constructor-arg>
</bean>

Hands-On:


🗂 6. Access Control Lists (ACLs) for Object Security

Concepts:

Configuration:

<bean id="aclPermissionEvaluator" class="org.springframework.security.acls.AclPermissionEvaluator">
    <constructor-arg ref="aclService"/>
</bean>

<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
    <property name="permissionEvaluator" ref="aclPermissionEvaluator"/>
</bean>

JavaConfig:

@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
    DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
    handler.setPermissionEvaluator(permissionEvaluator());
    return handler;
}

Hands-On:


✅ 7. Wrap-Up

Recap:

Best Practices:


📋 Instructor Notes: Setup Summary

Core Files:

Maven Dependencies:

Database Setup:

Testing Instructions

Troubleshooting Tips