Giter VIP home page Giter VIP logo

vains-sofia / oauth2-security-spring-boot-starter Goto Github PK

View Code? Open in Web Editor NEW
4.0 1.0 1.0 147 KB

该项目是对Spring OAuth2 Authorization Server的一个封装,利用Spring Boot 自动配置的特点可以快速的集成`Spring Authorization Server`框架,引入`starter` 后可以很方便的使用Spring Authorization Server原有功能,并且扩展功能也可以像其它Security的DSL配置方式进行配置。

License: Apache License 2.0

Java 100.00%

oauth2-security-spring-boot-starter's Introduction

简介

该项目是对Spring OAuth2 Authorization Server的一个封装,利用Spring Boot 自动配置的特点可以快速的集成Spring Authorization Server框架,引入starter 后可以很方便的使用Spring Authorization Server原有功能,并且扩展功能也可以像其它SecurityDSL配置方式进行配置。

为什么要封装?

之前出过一篇系列文章,读者在学习时总是会在各种莫名其妙的地方踩到坑,不小心错漏一个地方都需要排查半天;所以当时就萌生了一个封装starter 的想法,将一些扩展的功能以DSL的形式配置进认证服务的过滤器链中,直至现在算是有了一个雏形。

版本基础

  • Spring Boot 3.2.1
  • Spring Authorization Server
  • Spring Data Redis(可选)
  • Spring OAuth2 Client(可选)

这些依赖都随引用项目的SpringBoot版本决定使用的版本,如果以后无重大版本变化,则升级SpringBoot版本即可

特性列表

  • 全局验证码过滤器
  • 短信登录(只负责验证)
  • 邮箱登录(只负责验证)
  • OAuth2密码模式
  • 三方登录微信登录适配
  • 提供基于Redis的核心服务实现

快速开始

  1. 拉取代码
git clone https://gitee.com/vains-Sofia/oauth2-security-spring-boot-starter.git
  1. 安装至本地库
mvn clean install
  1. 在使用的项目中引入Maven坐标
<dependency>
    <groupId>com.vains</groupId>
    <artifactId>oauth2-security-spring-boot-starter</artifactId>
    <version>0.0.1</version>
</dependency>
  1. 添加认证服务配置,在认证服务配置中添加密码模式支持
/**
 * 配置端点的过滤器链
 *
 * @param http spring security核心配置类
 * @return 过滤器链
 * @throws Exception 抛出
 */
@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http)throws Exception{
    // 自定义配置 (重要:必须写在OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);之前,让该自定义配置在
    // OAuth2AuthorizationServerMetadataEndpointConfigurer配置之前)
    // 添加密码模式
    http.with(new ResourceOwnerPasswordConfigurer(),Customizer.withDefaults());

    // 配置默认的设置,忽略认证端点的csrf校验
    OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);

    http.getConfigurer(OAuth2AuthorizationServerConfigurer.class);
    // 其它认证服务配置

    return http.build();
}
  1. 添加资源服务器配置,在资源服务配置中添加邮箱、短信登录
/**
 * 配置认证相关的过滤器链
 *
 * @param http spring security核心配置类
 * @return 过滤器链
 * @throws Exception 抛出
 */
@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)throws Exception{    // ... 其它资源服务配置

    http.with(new BasicLoginConfigurer(),basicLoginConfigurer->basicLoginConfigurer
        // 添加短信登录,默认登录接口:/login/sms
        .smsCaptchaLogin(Customizer.withDefaults())
        // 添加邮件登录,默认登录接口:/login/email
        .emailCaptchaLogin(Customizer.withDefaults())
        // 当添加了短信登录或者邮件登录的配置时,默认添加验证码过滤器(这两种登录方式依赖验证码校验),或如下显示添加验证码配置
        .captchaAuthorization(Customizer.withDefaults())
    );

    // ... 其它资源服务配置

    return http.build();
}
  1. 生成验证码接口需要调用CaptchaRepository保存验证码信息
/**
 * 验证码接口
 *
 * @author vains
 */
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/captcha")
public class CaptchaController {

    private final CaptchaRepository captchaRepository;

    @GetMapping("/image")
    public BasicCaptcha imageCaptcha(HttpServletRequest request,
                                     HttpServletResponse response) {
        // 生成验证码

        ImageCaptcha imageCaptcha = new ImageCaptcha();
        imageCaptcha.setCode...
        imageCaptcha.setType(CaptchaType.IMAGE_CAPTCHA);

        captchaRepository.save(new ServletWebRequest(request, response), imageCaptcha);
        return imageCaptcha;
    }

    @GetMapping("/sms")
    public BasicCaptcha smsCaptcha(@NotBlank @RequestHeader String phone,
                                   HttpServletRequest request,
                                   HttpServletResponse response) {
        // 生成验证码
        log.debug("手机号[{}]获取验证码", phone);
        BasicCaptcha captcha = new BasicCaptcha();
        // 默认 1234
        captcha.setCode...
        captcha.setType(CaptchaType.SMS_CAPTCHA);

        captchaRepository.save(new ServletWebRequest(request, response), captcha);
        return captcha;
    }

    @GetMapping("/email")
    public BasicCaptcha emailCaptcha(HttpServletRequest request,
                                     HttpServletResponse response) {

        // 生成验证码
        BasicCaptcha captcha = new BasicCaptcha();
        captcha.setType(CaptchaType.EMAIL_CAPTCHA);
        // ...

        captchaRepository.save(new ServletWebRequest(request, response), captcha);
        return captcha;
    }

}

CaptchaRepository默认有两个实现,一个基于session,一个基于redis,当引入spring-boot-starter-data-redis依赖后自动使用基于redis的验证码存储库,否则使用基于session的验证码存储库。

配置说明

ResourceOwnerPasswordConfigurer

需要将它放在认证服务配置的第一行主要是为了在访问/.well-known/openid-configuration 时可以获取到自己添加的这个grant_type,否则获取不到,配置中也限制了只能添加在认证服务配置中。

配置 说明 默认
usernameParameter 设置密码模式登录账号的参数名 username
passwordParameter 设置密码模式登录密码的参数名 password
passwordGrantType 设置密码模式登录的grant_type值 password
tokenGenerator 设置密码生成器 HttpSecurity获取 --->>> 从ioc中获取 --->>> 创建一个实例
authenticationProvider 设置用户认证逻辑 DaoAuthenticationProvider
authorizationService 管理OAuth2流程中的认证信息 HttpSecurity获取 --->>> 从ioc中获取 --->>> 创建一个实例
grantAuthenticationTokenGenerator 自定义AuthenticationToken的生成,与authenticationProvider配合使用 默认生成UsernamePasswordAuthenticationToken

短信登录和邮件登录的配置

这两个配置类都继承自AbstractAuthenticationFilterConfigurer,也就是说这两个的配置项是和表单登录(Security 默认提供的formLogin配置项)的配置是一致的。

配置项captchaAuthorization对应的配置类CaptchaAuthorizationConfigurer

配置 说明 默认
captchaValidatorManager 验证码校验管理器 ioc中获取 --->>> DefaultCaptchaValidatorManager
captchaValidator 验证码校验器,如果设置该配置则默认的会被覆盖 短信、邮件、图片验证码校验
requestMatcher 设置验证码类型,对应需要检验的请求的地址、方式,验证码的参数名、获取验证码时的唯一id 短信、邮件登录默认表单登录
failureHandler 验证码校验失败处理 默认根据请求来源处理,页面请求跳转页面,ajax请求响应JSON

requestMatcher提供了多个重载的方法,可以简化写法; 关于requestMatcher也提供了yml的配置,如下

vains:
  captcha:
    validate:
      # 这里的image是type
      image:
        # code-parameter参数是验证码值的key
        code-parameter: image
        # 拦截的url(默认post),自己设置请求方式可以使用matcher-infos配置项
        request-uris: /captcha/sms,/captcha/email
        # request-uris配置项的配置实际上最终转换为matcher-infos了,所以两者等同,自选其一即可
        matcher-infos:
          # 请求地址
          - url: /captcha/sms
            # 请求方式
            http-method: POST
        # 设置image类型的验证码id在请求头/参数中的key
        cache-key: deviceId

原理

验证码校验

验证码校验流程

在验证码过滤器中根据当前请求在CaptchaValidatorManager中找到对应的验证码校验器,然后对当前请求进行校验,如果校验通过请求继续执行,校验失败调用配置的failureHandler进行验证失败处理。

graph TD
    start(浏览器发起请求) -->|通过CaptchaAuthorizationFilter| cFilter(CaptchaAuthorizationFilter)
    cFilter -->|是否需要校验| a(是否需要校验)
    a -->|无需校验| c(请求继续执行)
    a -->|需要校验| manager(CaptchaValidatorManager)
    c --> chain(过滤器链)

    manager -->|邮件验证码| email(EmailCaptchaValidator)
    manager -->|图片验证码| image(ImageCaptchaValidator)
    manager -->|短信验证码| sms(SmsCaptchaValidator)
    manager -->|其他验证器| other(...CaptchaValidator)

    email -->|需要校验| b(调用通用校验器验证)
    image -->|需要校验| d(调用通用校验器验证)
    sms -->|需要校验| e(调用通用校验器验证)
    other -->|需要校验| f(自定义验证实现)

    b -->|验证失败| failure(验证失败处理,响应)
    d -->|验证失败| failure
    e -->|验证失败| failure
    f -->|验证失败| failure

    b -->|验证成功| c
    d -->|验证成功| c
    e -->|验证成功| c
    f -->|验证成功| c

Loading

默认验证器说明

默认内置了三个验证器:EmailCaptchaValidatorImageCaptchaValidatorSmsCaptchaValidator,它们三个在引入依赖后会自动注入,调用的都是验证码的统一校验,在这三个校验器中根据配置(requestMatcher/yml)决定是否需要校验和封装参数调用统一验证码校验处理。它们在IOC中的名称分别是emailimagesms,如果想重写对应的校验逻辑只需要在注入时设置bean的名字即可覆盖。

验证器扩展说明

starter提供了AbstractCaptchaValidator类,继承该类注入ioc后会自动根据bean名称去找验证码配置(requestMatcher/yml)中的配置,根据配置自动拦截、校验配置的请求路径,验证码配置(requestMatcher/yml)中的type和bean的名字是对应的,所以如果继承该类实现自己的校验逻辑记得要一一对应。

starter中注入代码如下,去掉@ConditionalOnMissingBean(name = ...)注解,注入自己的实现即可

@Bean(DefaultConstants.SMS_CAPTCHA_VALIDATE)
@ConditionalOnMissingBean(name = DefaultConstants.SMS_CAPTCHA_VALIDATE)
public CaptchaValidator smsCaptchaValidator(CaptchaRepository captchaRepository) {
    return new SmsCaptchaValidator(captchaRepository, captchaValidateProperties);
}

@Bean(DefaultConstants.EMAIL_CAPTCHA_VALIDATE)
@ConditionalOnMissingBean(name = DefaultConstants.EMAIL_CAPTCHA_VALIDATE)
public CaptchaValidator emailCaptchaValidator(CaptchaRepository captchaRepository) {
    return new EmailCaptchaValidator(captchaRepository, captchaValidateProperties);
}

@Bean(DefaultConstants.IMAGE_CAPTCHA_VALIDATE)
@ConditionalOnMissingBean(name = DefaultConstants.IMAGE_CAPTCHA_VALIDATE)
public CaptchaValidator imageCaptchaValidator(CaptchaRepository captchaRepository) {
    return new ImageCaptchaValidator(captchaRepository, captchaValidateProperties);
}

CaptchaValidator继承类图

graph TB
	base(CaptchaValidator) --> abstract(AbstractCaptchaValidator)
	abstract --> email(EmailCaptchaValidator)
	abstract --> image(ImageCaptchaValidator)
	abstract --> sms(SmsCaptchaValidator)
Loading

验证码存储

默认验证码存储结构

验证码存储是通过实现CaptchaRepository接口来实现存储,接口中提供了三个抽象方法对验证码进行操作,AbstractCaptchaRepository抽象类实现了该接口,并提供了获取缓存key的方法,子类可直接使用,但是限制了子类在实例化时必须传入CaptchaValidateProperties的实例,因为要根据验证码类型获取配置文件中配置的缓存key在请求头/请求参数中的key,这里就跟前面说明配置的地方对应上了。

默认实现

默认有两个实现,一个基于Redis、一个基于session存储,分别是RedisCaptchaRepositorySessionCaptchaRepository,如果项目有引入spring-boot-starter-data-redis会自动注入RedisCaptchaRepository,否则会自动注入SessionCaptchaRepository如果想使用自己的存储实现,可以直接注入自己的实现,如下:

@Bean
public CaptchaRepository sessionCaptchaRepository(CaptchaValidateProperties captchaValidateProperties) {
    return new SessionCaptchaRepository(captchaValidateProperties);
}

上方配置即可替换默认行为。

CaptchaRepository类图

graph TB
	base(CaptchaRepository) --> abstract(AbstractCaptchaRepository)
	abstract --> redis(RedisCaptchaRepository)
	abstract --> session(SessionCaptchaRepository)
Loading

短信登录、邮件登录

这两个处理登录的过滤器都是继承自AbstractAuthenticationProcessingFilter,与默认的UsernamePasswordAuthenticationFilter过滤器逻辑基本一致,唯一的区别就是过滤器内生成token不同,因为这两种方式不需要校验密码(过滤器链最前边有验证码过滤器),所以交给各自的provider处理,配置类也跟原配置中的formLogin配置基本一致,跟原生账号密码登录配置是一样的配置方式。

oauth2-security-spring-boot-starter's People

Contributors

vains-sofia avatar

Stargazers

yang avatar SLIGHTLEE avatar oc avatar shuigedeng avatar

Watchers

 avatar

Forkers

shuigedeng

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.