SpringSecurity 4.1.4 认证( authentication)流程分析 Restful认证扩展

Spring Security主要针对应用的“认证(authentication)” 和 “授权(authorization)”两个部分进行处理工作.“认证(authentication)”负责建立主体(principal),主体可以是一个用户,一个设备,或者其他可以在我们的应用中执行某种操作的东西。" Authorization "指的是判断某个 principal 在我们的应用是否允许执行某个操作。在 进行授权判断之前,要求其所要使用到的规则必须在验证过程中已经建立好了.

本文只讨论前半段“认证(authentication)”部分. 且因为我们的项目使用Spring Security 4.1.4,所以文中引用的源码都摘自4.1.4版本.

认证方式(模型)

Spring Security支持的认证模型非常多,官方文档里面有详细介绍spring-security 4.1.4.RELEASE-reference
各种认证模型的加密方式, 认证算法, 用户信息存放结构等各不相同, 但从客户端的角度来看, 其认证流程基本相同.

认证流程

  1. 用户输入username和password
  2. 进行用户名密码校验, 并校验该用户的有效性
  3. 后台保持其登陆状态
  4. 向客户端返回认证凭证(Token)
  5. 客户端携带Token进行业务访问
  6. 服务器校验Token的有效性
  7. 获取用户信息, 构建主体(Principal)

之后根据构建出的Principal进行授权校验, 允许或拒绝业务请求.(后续工作为授权相关内容, 本文暂不讨论)

Form-based authentication 源码分析

传统Web项目中最常用,最基础的认证方式就是基于Form表单的用户名密码认证, 本文后续会讲解的Restful认证模型也基于Form-based authentication来扩展.

Filter

所有使用用户名密码的认证请求都会由 UsernamePasswordAuthenticationFilter 进行处理, 其doFilter方法继承于其父类 AbstractAuthenticationProcessingFilter

先来看 AbstractAuthenticationProcessingFilter 中的doFilter方法关键代码(212行), 此处进行了用户认证操作.

authResult = attemptAuthentication(request, response);

在 AbstractAuthenticationProcessingFilter 中 attemptAuthentication 方法是抽象方法, UsernamePasswordAuthenticationFilter 中对其进行了实现.

UsernamePasswordAuthenticationFilter 中的 attemptAuthentication 方法:

public Authentication attemptAuthentication(HttpServletRequest request,
        HttpServletResponse response) throws AuthenticationException {
    if (postOnly && !request.getMethod().equals("POST")) {
        throw new AuthenticationServiceException(
                "Authentication method not supported: " + request.getMethod());
    }
    // 获取用户名,密码
    String username = obtainUsername(request);
    String password = obtainPassword(request);

    if (username == null) {
        username = "";
    }

    if (password == null) {
        password = "";
    }

    username = username.trim();
    // 构造用户名密码的认证对象
    UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
            username, password);

    // Allow subclasses to set the "details" property
    setDetails(request, authRequest);
    // 执行校验(使用DaoAuthenticationProvider进行校验)
    return this.getAuthenticationManager().authenticate(authRequest);
}

到此完成了认证流程中1,2两步

  • 用户输入username和password
  • 进行用户名密码校验, 并校验该用户的有效性

第3步的实现则要返回到 AbstractAuthenticationProcessingFilter 中.

  • 后台保持其登陆状态

首先来看第218行代码, 根据设置的SessionStrategy(session策略),进行session操作, 如将用户信息存入session中.

sessionStrategy.onAuthentication(authResult, request, response);

传统Web项目是用Cookie来保存sessionID, 自然在Spring Security默认的Form-base认证体系中不需要特别处理认证凭证的返回问题, 客户端在首次访问登陆页面时已经获取到sessionID, 并使用Cookie存储在客户端, 并携带在之后的每次请求中. 因此下3步都由Web架构默认处理.

  • 向客户端返回认证凭证(Token)
  • 客户端携带Token进行业务访问
  • 服务器校验Token的有效性

最后一步首先要从后台持久化登陆状态(session)中获取用户信息, 然后再用这些信息来构建主体. 注意目前的客户端请求并不是登陆请求而是普通的业务请求, 与 UsernamePasswordAuthenticationFilter 没有关系, 而是会在 SecurityContextPersistenceFilter 中进行处理.

  • 获取用户信息, 构建主体(Principal)

第100行代码进行了用户信息获取操作并根据用户类型构建Principal, 本文中构建的是User对象; 第114行代码对持久化用户信息做处理.

// 获取用户信息, 并构建主体(Principal)
SecurityContext contextBeforeChainExecution = repo.loadContext(holder);

// 对持久化对象做处理
repo.saveContext(contextAfterChainExecution, holder.getRequest(),
                holder.getResponse());

到此,对 Spring Security 默认的 Form-base 认证流程做了简要概述. 以此为基础, 下面开始具体分析如何建立合理的Restful API的认证体系, 以及如何纳入Spring Security的认证体系中.

Restful 认证改造

因为Restful的无状态原则, session的所有操作都要禁用,所以 SessionStrategy 就不再赘述. 再看第240行代码:

successfulAuthentication(request, response, chain, authResult);

进行认证成功之后的操作, 其中进行了RememberMe(如果启用)等相关处理, 最后调用了

successHandler.onAuthenticationSuccess(request, response, authResult);

用于自定义认证成功之后的处理方法.

转载于:https://www.cnblogs.com/hunter-phang/p/7044331.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值