Understanding Session-Based Authentication and Single Sign-On (SSO) with CAS and OAuth2

This article explains the challenges of multiple product systems, reviews traditional session mechanisms and their limitations in clustered environments, compares session replication and centralized storage using Redis, and details the design and implementation of Single Sign-On using CAS and OAuth2 with Java Spring code examples.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Understanding Session-Based Authentication and Single Sign-On (SSO) with CAS and OAuth2

When a company has many products, users must repeatedly log in to each system, leading to poor experience and increased password management costs; unifying authentication across the product matrix can improve usability and security.

Traditional Session Mechanism

HTTP is stateless, so servers create a new session for each request; the session ID (often JSESSIONID) is stored in a cookie or URL rewrite. The server checks the cookie for a session ID, retrieves the session data from memory, or creates a new session if none exists.

In a clustered environment, a user's request may be routed to different servers, causing session loss because the session is stored locally on each server.

Session Sharing Solutions

Two main approaches are session replication (copying session data to all nodes) and centralized session storage (using a shared store such as Redis). Centralized storage avoids synchronization overhead and is commonly implemented with Redis.

Single Sign-On (SSO) Concept

SSO allows a user to log in once and access multiple systems without re-authenticating, typically by issuing a ticket that links the user’s identity across services.

CAS (Central Authentication Service) Flow

1. User accesses a protected service (b.com) and is redirected to the central login domain (ouath.com). 2. After successful login, a ticket is generated and stored in Redis as {ticket: sessionId}. 3. The user is redirected back to the original service with the ticket. 4. The service retrieves the session ID from Redis using the ticket, creates a local session, and redirects the user to the original URL.

Code Demonstration

User entity:

public class UserForm implements Serializable {
    private static final long serialVersionUID = 1L;
    private String username;
    private String password;
    private String backurl;
    // getters and setters omitted for brevity
}

Login controller (Spring MVC):

@Controller
public class IndexController {
    @Autowired
    private RedisTemplate redisTemplate;

    @GetMapping("/toLogin")
    public String toLogin(Model model, HttpServletRequest request) {
        Object userInfo = request.getSession().getAttribute(LoginFilter.USER_INFO);
        if (userInfo != null) {
            String ticket = UUID.randomUUID().toString();
            redisTemplate.opsForValue().set(ticket, userInfo, 2, TimeUnit.SECONDS);
            return "redirect:" + request.getParameter("url") + "?ticket=" + ticket;
        }
        UserForm user = new UserForm();
        user.setUsername("laowang");
        user.setPassword("laowang");
        user.setBackurl(request.getParameter("url"));
        model.addAttribute("user", user);
        return "login";
    }

    @PostMapping("/login")
    public void login(@ModelAttribute UserForm user, HttpServletRequest request, HttpServletResponse response) throws IOException {
        request.getSession().setAttribute(LoginFilter.USER_INFO, user);
        String ticket = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(ticket, user, 20, TimeUnit.SECONDS);
        if (user.getBackurl() == null || user.getBackurl().length() == 0) {
            response.sendRedirect("/index");
        } else {
            response.sendRedirect(user.getBackurl() + "?ticket=" + ticket);
        }
    }

    @GetMapping("/index")
    public ModelAndView index(HttpServletRequest request) {
        ModelAndView mv = new ModelAndView();
        UserForm user = (UserForm) request.getSession().getAttribute(LoginFilter.USER_INFO);
        mv.setViewName("index");
        mv.addObject("user", user);
        return mv;
    }
}

Login filter to protect resources:

public class LoginFilter implements Filter {
    public static final String USER_INFO = "user";
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        Object userInfo = request.getSession().getAttribute(USER_INFO);
        String url = request.getServletPath();
        if (!"/toLogin".equals(url) && !url.startsWith("/login") && userInfo == null) {
            request.getRequestDispatcher("/toLogin").forward(request, response);
            return;
        }
        chain.doFilter(request, response);
    }
}

Spring configuration for the filter:

@Configuration
public class LoginConfig {
    @Bean
    public FilterRegistrationBean sessionFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new LoginFilter());
        registration.addUrlPatterns("/*");
        registration.setName("sessionFilter");
        registration.setOrder(1);
        return registration;
    }
}

Additional SSO filter (SSOFilter) demonstrates ticket validation against Redis and session creation, and the corresponding controller and view templates are provided.

CAS vs OAuth2

CAS is a centralized authentication service that issues tickets for web SSO, focusing on protecting client‑side resources; OAuth2 is an authorization framework that allows third‑party applications to access a resource server on behalf of a user, protecting server‑side resources.

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.

JavaspringCASOAuth2Session ManagementSSO
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

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.