【Spring Security OAuth2笔记系列】- spring security -短信登录配置及重构

短信登录配置及重构

重构思路:

  1. 重构不是更改已有的功能
  2. 重构是不影响已有功能的情况下,对已有代码进行抽象封装
  3. 多处使用相同代码的地方,需要抽出来
  4. 比如上章节的很多代码,

    如:图形验证码过滤器和短信验证码过滤器重复代码太多
    服务接口的url地址和过滤器中的过滤器地址重复
    等..

系统配置相关的代码结构

core项目中的重构如下:

  • 密码登录的配置代码
  • 短信登录的配置代码
  • 验证码相关的配置代码

browser项目:

  • BrowserSecurityConfig
  • 只留下浏览器特有的配置代码
    • 如记住我的功能,只有浏览器特有这样的功能

app:

  • AppSecurityConfig
  • App特有的配置代码

通过配置apply功能进行配置的引用
【Spring Security OAuth2笔记系列】- spring security -短信登录配置及重构_第1张图片

感受

花了6个小时看老师重构之后的代码,然后完成了自己跟练的项目代码;

太厉害!!这个重构技巧太牛逼了;

总之:当有两处重复代码的时候 就要抽取代码了。这个需要大量的经验才能不分类好,不至于越抽越乱

这里再啰嗦下:
关于用户名密码登录和短信登录表单提交的url地址,不需要真实存在,
因为这个是提供这两个特定过滤器框架特定的拦截点。只有提交到指定的拦截点,
才会进入认证功能服务

此次重构一些知识点

  • 善用 HttpSecurity.apply 应用分离之后的配置类
  • 程序中有手动写字符串2次的就抽成 SecurityConstants 常量接口类
  • 善用 Autowired注解提供的 依赖查找功能
  • 善用 类名统一起名
  • 善用枚举类 提供相应的支持

善用 HttpSecurity.apply 应用分离之后的配置类

 HttpSecurity.apply 方法跟踪进来是父类的;这里是一个泛型,所有需要看HttpSecurity对应传递的是什么类型
public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>>
        extends AbstractSecurityBuilder<O> {
      public > C apply(C configurer)
        throws Exception {
        configurer.addObjectPostProcessor(objectPostProcessor);
        configurer.setBuilder((B) this);
        add(configurer);
        return configurer;
      }

--------- HttpSecurity 声明
public final class HttpSecurity extends
        AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
        implements SecurityBuilder<DefaultSecurityFilterChain>,
        HttpSecurityBuilder<HttpSecurity> {

------------ 注意看对比
public > C apply(C configurer

AbstractConfiguredSecurityBuilder

这里的c对应的泛型就是  ,而O,B对应到HttpSecurity的声明就是

HttpSecurity.apply 返回一个SecurityConfigurerAdapter,所以这里只要继承该类,就是apply需要的对象了

------------- 如下示例
/**
 * 验证码配置
 * @author : zhuqiang
 * @version : V1.0
 * @date : 2018/8/5 20:05
 */
@Component
public class ValidateCodeSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
    /**
     * @see ValidateCodeFilter  目前融合了短信和图形验证码的验证功能
     */
    @Autowired
    private Filter validateCodeFilter;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        // 由源码得知,在最前面的是UsernamePasswordAuthenticationFilter
        http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class);
    }
}

SecurityConstants 常量接口类

在重构中就已经发现这样做的好处了。因为这个代码被分离写和配置的,老是忘记在哪些地方用过
在修改的时候经常忘记修改,或则找不到,所以需要抽成常量类

public interface SecurityConstants {

    /**
     * 默认的处理验证码的url前缀
     */
    public static final String DEFAULT_VALIDATE_CODE_URL_PREFIX = "/code";

善用 Autowired注解提供的 依赖查找功能

把多个实现类统一管理,特别是使用模板方法抽取公用逻辑的时候,就拍上用处了
如下代码,还提供了按beanName查找指定的子类实现;
还提供了按自定义类型,下面会讲到善用命名会在某些地方起到奇效

/**
 * 处理器持有者,用来管理所有验证码类型的处理器
 * @author : zhuqiang
 * @version : V1.0
 * @date : 2018/8/5 20:40
 */
@Component
public class ValidateCodeProcessorHolder {
    @Autowired
    private Map validateCodeProcessors;

    public ValidateCodeProcessor findValidateCodeProcessor(ValidateCodeType type) {
        return findValidateCodeProcessor(type.toString().toLowerCase());
    }

    public ValidateCodeProcessor findValidateCodeProcessor(String type) {
        String beanName = type.toLowerCase() + ValidateCodeProcessor.class.getSimpleName();
        ValidateCodeProcessor processor = validateCodeProcessors.get(beanName);
        if (processor == null) {
            throw new ValidateCodeException("验证码处理器 " + beanName + " 不存在");
        }
        return processor;
    }
}

善用 类名统一起名

如这里的几个类

  • ValidateCodeProcessor 验证码处理接口
  • ImageValidateCodeProcessor 图片验证码处理接口
  • SmsValidateCodeProcessor 短信验证码处理接口

这里的前缀,配合上面的技巧 善用 Autowired注解提供的 依赖查找功能,使用以下代码就能方便的获取到对应的处理器

他们都一个共同的父类,有公用的步骤,变化的部分由子类实现;
public abstract class AbstractValidateCodeProcessor<C extends ValidateCode> implements ValidateCodeProcessor {
  /**
   * 根据请求的url获取校验码的类型:
   * ValidateCodeProcessorHolder : 中持有所有本类的子类型,获取getClass能拿到具体的实例类名
   * @return
   * @see ValidateCodeProcessorHolder
   */
  private ValidateCodeType getValidateCodeType() {
      // 处理器 命名规则:ImageValidateCodeProcessor,拿到前缀即可
      // 返回 Image
      String type = StringUtils.substringBefore(getClass().getSimpleName(), ValidateCodeProcessor.class.getSimpleName());
      return ValidateCodeType.valueOf(type.toUpperCase());
  }
}

在外部使用 type + ValidateCodeProcessor.class.getSimpleName() 就能获取到完整的类名,
也就能使用ValidateCodeProcessorHolder动态的获取处理器了

善用枚举类提供相应的支持

枚举类的名称是 短信和图片验证功能的前缀。配合上面的几条。
在使用模板方法模式抽取公用逻辑的时候,可以使用前缀获取不同功能支持的动态常量等类容
在外部要动态使用服务的时候,也能用前缀+具体的的父类命名获取到

public enum ValidateCodeType {
    /**
     * 短信验证码
     */
    SMS {
        @Override
        public String getParamNameOnValidate() {
            return SecurityConstants.DEFAULT_PARAMETER_NAME_CODE_SMS;
        }
    },
    /**
     * 图片验证码
     */
    IMAGE {
        @Override
        public String getParamNameOnValidate() {
            return SecurityConstants.DEFAULT_PARAMETER_NAME_CODE_IMAGE;
        }
    };

    /**
     * 校验时从请求中获取的参数的名字
     * @return
     */
    public abstract String getParamNameOnValidate();
}

你可能感兴趣的:(spring,security+oauth2)