给 Spring Security OAuth 增加新的授权模式

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 【6月更文挑战第1天】这篇我们来试着参考密码模式,给 Spring Security OAuth 增加一个手机验证码模式。以下内容会与之前的文章内容有关联,因此在此之前,可以先阅读之前的几篇文章,回顾一下这些内容。

由于内容相关联,我先列几篇之前的文章,欢迎阅读:

以上三篇文章分别分析了,Spring Security 是怎么完成用户认证的、如何给 Spring Security 增加新的认证逻辑(手机验证码)、Spring Security OAuth 密码模式(资源所有者模式)是如何完成认证的。

这篇我们来试着参考密码模式,给 Spring Security OAuth 增加一个手机验证码模式。以下内容会与之前的文章内容有关联,因此在此之前,可以先阅读之前的几篇文章,回顾一下这些内容。

本文有大量内容会用到 Spring Security 自定义认证逻辑 这篇文章里创建的 Java 类,强烈建议你先读一下。

实现 Granter

首先需要实现一个与 ResourceOwnerPasswordTokenGranter 类似的、手机验证码模式对应的 Granter 类,继承 AbstractTokenGranter

我们根据 ResourceOwnerPasswordTokenGranter 照猫画虎,写一个 SmsTokenGranter

public class SmsTokenGranter extends AbstractTokenGranter {

    private static final String GRANT_TYPE = "sms";

    private final AuthenticationManager authenticationManager;

    public SmsTokenGranter(AuthenticationManager authenticationManager,
                           AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
        this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
    }

    protected SmsTokenGranter(AuthenticationManager authenticationManager, AuthorizationServerTokenServices tokenServices,
                                                ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, String grantType) {
        super(tokenServices, clientDetailsService, requestFactory, grantType);
        this.authenticationManager = authenticationManager;
    }

    @Override
    protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {

        Map<String, String> parameters = new LinkedHashMap<String, String>(tokenRequest.getRequestParameters());
        String username = parameters.get("mobile");
        String password = parameters.get("smsCode");

        Authentication userAuth = new SmsCodeAuthenticationToken(username, password);
        ((AbstractAuthenticationToken) userAuth).setDetails(parameters);
        try {
            userAuth = authenticationManager.authenticate(userAuth);
        }
        catch (AccountStatusException ase) {
            //covers expired, locked, disabled cases (mentioned in section 5.2, draft 31)
            throw new InvalidGrantException(ase.getMessage());
        }
        catch (BadCredentialsException e) {
            // If the username/password are wrong the spec says we should send 400/invalid grant
            throw new InvalidGrantException(e.getMessage());
        }
        if (userAuth == null || !userAuth.isAuthenticated()) {
            throw new InvalidGrantException("Could not authenticate user: " + username);
        }

        OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
        return new OAuth2Authentication(storedOAuth2Request, userAuth);
    }
}

这是已完成的代码,根据 ResourceOwnerPasswordTokenGranter 修改而来,需要关注的地方有两个:

  1. 代码第 3 行,GRANT_TYPE = "sms",认证类型为 sms。OAuth 2.0 共包含四种模式,分别是authorization_codeimplicitpasswordclient_credential。我们现在为其添加 sms 模式。
  2. 代码第 22 到 25 行,从请求中获取手机号和验证码参数,然后封装成一个 SmsCodeAuthenticationToken 对象。SmsCodeAuthenticationToken 也是我们为手机验证码模式创建的类,在 Spring Security 自定义认证逻辑 中已经写过了,具体的写法和作用,可以参考这篇文章。

Authentication 和 AuthenticationProvider

SmsCodeAuthenticationToken 是我们为了手机验证码模式创建的 Authentication 实现类。另外,在 SmsTokenGranter 的 getOAuth2Authentication 方法中,还有一行关键的代码:

userAuth = authenticationManager.authenticate(userAuth);

如果你阅读了文章开头的关联文章,你应该了解这句代码调用的方法背后,实现了认证的逻辑,并且,这里需要实现一个与手机验证码模式对应的 AuthenticationProvider 类,这个类我们在之前的文章里也是先过了,参考 Spring Security 自定义认证逻辑SmsCodeAuthenticationProvider 实现的部分。

配置

以上就是所有需要创建的类,接下来完成配置。

这里有个前提,就是已经配置好了 Spring Security OAuth 的功能,以下内容直接少我们需要在此基础上需要增加那些配置。

首先,在 Spring Security OAuth 的授权服务器配置类,也就是 AuthorizationServerConfigurerAdapter 的子类中的 configure(AuthorizationServerEndpointsConfigurer endpoints) 方法中,添加如下配置:

List<TokenGranter> tokenGranters = new ArrayList<>();

tokenGranters.add(new AuthorizationCodeTokenGranter(endpoints.getTokenServices(), endpoints.getAuthorizationCodeServices(), clientDetailsService,
        endpoints.getOAuth2RequestFactory()));
tokenGranters.add(new RefreshTokenGranter(endpoints.getTokenServices(), clientDetailsService, endpoints.getOAuth2RequestFactory()));
ImplicitTokenGranter implicit = new ImplicitTokenGranter(endpoints.getTokenServices(), clientDetailsService, endpoints.getOAuth2RequestFactory());
tokenGranters.add(implicit);
tokenGranters.add(new ClientCredentialsTokenGranter(endpoints.getTokenServices(), clientDetailsService, endpoints.getOAuth2RequestFactory()));
if (authenticationManager != null) {
    tokenGranters.add(new ResourceOwnerPasswordTokenGranter(authenticationManager, endpoints.getTokenServices(), clientDetailsService, endpoints.getOAuth2RequestFactory()));
}
tokenGranters.add(new SmsTokenGranter(authenticationManager, endpoints.getTokenServices(),
        clientDetailsService, endpoints.getOAuth2RequestFactory()));

endpoints.tokenGranter(new CompositeTokenGranter(tokenGranters));

以上代码中,就是将 Spring Security OAuth 内置的四种授权模式的 Granter 添加到一个列表中,再将我们刚才创建的 SmsTokenGranter 添加进去,最后在封装成一个 CompositeTokenGranter 并配置到 endpoints 中。

这里可以参考下之前的这篇文章:Spring Security OAuth 之 @EnableAuthorizationServer 干了啥?

然后,在 Spring Security 的配置类,也就是 WebSecurityConfigurerAdapter 的子类中,添加 SmsCodeAuthenticationProvider 的 Bean:

@Bean
public SmsCodeAuthenticationProvider smsCodeAuthenticationProvider() {
    SmsCodeAuthenticationProvider smsCodeAuthenticationProvider = new SmsCodeAuthenticationProvider();
    smsCodeAuthenticationProvider.setUserDetailsService(userDetailsService);
    return smsCodeAuthenticationProvider;
}

再在 configure(HttpSecurity http) 将其配置到 http 中:

http.authenticationProvider(smsCodeAuthenticationProvider())

其余的诸如发送验证码接口等内容,参考之前的文章。

测试

image.png

image.png

目录
相关文章
|
2天前
|
JSON 安全 Java
Spring Security 6.x 微信公众平台OAuth2授权实战
上一篇介绍了OAuth2协议的基本原理,以及Spring Security框架中自带的OAuth2客户端GitHub的实现细节,本篇以微信公众号网页授权登录为目的,介绍如何在原框架基础上定制开发OAuth2客户端。
20 4
Spring Security 6.x 微信公众平台OAuth2授权实战
|
5天前
|
存储 安全 Java
Spring Security 6.x OAuth2登录认证源码分析
上一篇介绍了Spring Security框架中身份认证的架构设计,本篇就OAuth2客户端登录认证的实现源码做一些分析。
31 2
Spring Security 6.x OAuth2登录认证源码分析
|
9天前
|
安全 Java 数据安全/隐私保护
Spring Security 6.x 一文快速搞懂配置原理
本文主要对整个Spring Security配置过程做一定的剖析,希望可以对学习Spring Sercurity框架的同学所有帮助。
40 5
Spring Security 6.x 一文快速搞懂配置原理
|
6天前
|
安全 Java API
Spring Security 6.x 图解身份认证的架构设计
【6月更文挑战第1天】本文主要介绍了Spring Security在身份认证方面的架构设计,以及主要业务流程,及核心代码的实现
16 1
Spring Security 6.x 图解身份认证的架构设计
|
5天前
|
Java Docker 容器
使用 Spring Boot 构建 Docker 镜像并进行多模式部署
使用 Spring Boot 构建 Docker 镜像并进行多模式部署
24 2
|
6天前
|
安全 前端开发 Java
CSRF 攻击以及如何使用 Spring Security 预防攻击
【6月更文挑战第15天】CSRF 是指跨站请求伪造,是 Cross-site request forgery 的简称,有些地方也简写为 XSRF。
328 1
|
8天前
|
安全 前端开发 Java
Spring Security 6.x 过滤器链SecurityFilterChain是如何工作的
上一篇主要介绍了Spring Secuirty中的过滤器链SecurityFilterChain是如何配置的,那么在配置完成之后,SecurityFilterChain是如何在应用程序中调用各个Filter,从而起到安全防护的作用,本文主要围绕SecurityFilterChain的工作原理做详细的介绍。
39 0
Spring Security 6.x 过滤器链SecurityFilterChain是如何工作的
|
4天前
|
Java 测试技术 数据安全/隐私保护
微信授权就是这个原理,Spring Cloud OAuth2 授权码模式
微信授权就是这个原理,Spring Cloud OAuth2 授权码模式
|
4天前
|
存储 安全 Java
spring security原理-学习笔记1-整体概览
spring security原理-学习笔记1-整体概览
|
5天前
|
缓存 安全 Java
【权限管理系统】Spring security(三)---认证过程(原理解析,demo)
【权限管理系统】Spring security(三)---认证过程(原理解析,demo)

热门文章

最新文章