AgileFramework系列组件——agile-security权限认证组件

agile-security : 权限认证组件

该组件是在spring-security基础上,做了大量的定制化开发,使其支持已最简单的方式应用于我们的系统当中。
并且最大化遵循spring-security原生的设计思路,避免重复不必要的设计。设计过程中预留了相当多的可扩展接口,最大限度支持
二次开发。组件特色是在前后端分离场景下做了大量支持,默认使用缓存方式做账户信息存储。

源码地址:https://gitee.com/agile-framework/agile-security


它有什么作用

  • JWT+自动令牌延时+主动失效
    token由JWT方式生成,并通过缓存组件agile-cache为其增加了令牌自动延时与主动失效功能

  • 可定制令牌传输途径
    内置响应头(header)与cookie两种令牌传输方式,可以根据实际场景的安全级别,调整令牌传输途径。

  • 动态令牌
    提供简单、复杂两种令牌生成策略,默认简单策略为登陆到退出时间段内共享一个有效令牌。复杂策略为每次前后端通信均采用新令牌,并将上一次
    通信令牌失效,确保每次前后端通信令牌唯一。但复杂令牌需前端做响应支持,当出现某一次令牌传输失败,有可能面临后续通信全部视为非法请求
    的情况,所以复杂策略在没有确保前后端高度配合的情况下,一般不建议使用

  • 为账户定制单独的登录测录
    这里的登录策略分为

单例(同一时间同一帐号系统中只能存活一个有效登录)
多例(同一时间同一帐号系统中只能存活一个有效登录)
单点(同一帐号,在agile-security微服务或集群中,仅需登录一次)
  • 可定制
`cloud.agileframework.security.provider`包下提供多扩展点(钩子函数),如:
`cloud.agileframework.security.provider.LoginValidateProvider`登录验证点,当产生帐号登录事件后,会触发该扩展点,且提供前端输入的帐号、密码、请求与响应等信息,扩展点通过抛出`AuthenticationException`类异常
进行非法登录识别
`cloud.agileframework.security.provider.PasswordProvider`密码解密点,当产生帐号登录事件后,会触发一次该扩展点,提供前端传输到服务端的密码,一般用于前后端密码约定密码加密,防止密码泄露的场景当中
`cloud.agileframework.security.provider.SecurityResultProvider`认证结果视图处理点,当发生登录成功、失败、权限认证失败等事件时,会触发该扩展点,提供相应的如异常、帐号信息等必要信息,用于制定符合自己需要的响应报文以及结果处理
`cloud.agileframework.security.provider.LogoutProcessorProvider`退出点,当产生帐号退出事件后,会触发该扩展点,且提供退出帐号及令牌信息
  • 持久化数据
    默认提供内存方式账户数据持久化,开发者可根据实际需要向spring
    容器中注入以下两类接口,实现对自定义持久化方式,如使用MySQL存储、为账户信息扩展邮箱、住址等等定制化需求
`cloud.agileframework.security.filter.login.CustomerUserDetails`账户信息结构
`cloud.agileframework.security.filter.login.CustomerUserDetailsService` 账户数据操作
  • 集群、分布式
    组件认证是采用无状态化服务将关键认证数据存储于缓存,其中缓存部分由agile-cache提供,当分布式或集群场景中时,可将agile-cache配置为redis等三方缓存方式,即可实现无状态化服务方式认证。

  • 验证码
    验证码由agile系列spring-boot-starter-kaptcha组件提供,并内置验证码组件开关以及样式等元数据方式配置。该验证码同样支持分布式/集群等方式认证,避免验证码颁发与验证不在同一服务器时无法验证的问题。

  • 密码强度校验
    工具cloud.agileframework.security.util.PasswordUtil中提供了对密码强度的校验,并且支持扩展校验规则以及规则权重。校验结果为百分制,通过判断如AABB、ABCABC、键盘连续字母、数字、关键词、长度、字符种类等等诸多规则,结合响应规则权重,判断密码强度。

  • 模拟账户
    可以通过提供json形式的模拟帐号信息,用于开发测试,

  • 失败次数限制
    支持超过登录失败次数后根据登录限制锁,锁定登录的能力。并且登录失败计数间隔、锁定时长等等均可配。

  • 登录限制锁
    内置三种登录限制对象,可单独或混合使用,如锁定指定ip下的指定浏览器会话;指定ip下的指定帐号等等。

    浏览器会话(sessionId)
    帐号(客户端请求登录的帐号)
    ip(客户端ip)
  • MVC账号类型参数解析
    内置了帐号相关的参数类型解析,支持在控制层中识别UserDetails类型参数

快速入门

开始你的第一个项目是非常容易的。

步骤 1: 下载包

您可以从[最新稳定版本]下载包(https://github.com/mydeathtrial/agile-security/releases).
该包已上传至maven中央仓库,可在pom中直接声明引用

以版本agile-security-2.0.0.jar为例。

步骤 2: 添加maven依赖
<!--声明中央仓库-->
<repositories>
    <repository>
        <id>cent</id>
        <url>https://repo1.maven.org/maven2/</url>
    </repository>
</repositories>
<!--声明依赖-->
<dependency>
    <groupId>cloud.agileframework</groupId>
    <artifactId>agile-security</artifactId>
    <version>2.0.0</version>
</dependency>
步骤 3: 配置开关
agile.security.enable=true
步骤 4: 登录/退出
  • 默认登录地址/login?username=admin&password=password
  • 默认退出地址/logout

配置说明

# 认证组件开关,该开关不限制模拟账户功能
agile.security.enable=true
# 排除认证地址
agile.security.exclude-url=${agile.kaptcha.url},/swagger-ui.html,/webjars/springfox-swagger-ui/*,/v2/api-docs,/swagger-resources/**,/api/password-find
# 退出地址
agile.security.login-out-url=/api/logout
# 登录地址
agile.security.login-url=/api/login
# 登录时前端提交的帐号属性key
agile.security.login-username=username
# 登录时前端提交的密码属性key
agile.security.login-password=password
# 验证码会话令牌key,用于分布式验证码支持,一般存于cookies
agile.security.verification-code=authCode
# 身份令牌过期时间,过期从最后一次服务器接收请求开始计算
agile.security.token-timeout=30m
# 身份令牌存储key,一般存于cookies或header中
agile.security.token-header=authToken
# 身份令牌传输途径,支持cookie、header头信息,可配置多个
agile.security.token-transmission-mode=cookie,header
# 身份令牌加密盐值
agile.security.token-secret=23617641641
# 身份令牌策略,easy(简单方式,不刷新),difficult(复杂方式,每次通信后刷新身份令牌)
agile.security.token-type=easy
# 客户端真实IP,请求头传输参数名
agile.security.real-ip-header=X-Real-Ip

# 密码强度
# 密码最低强度(暂未使用)
agile.security.password.strength=5
# 密码有效期 (暂未使用)
agile.security.password.duration=31d
# 密码传输密钥 (暂未使用)
agile.security.password.key=167223764989834
# 密码传输偏移量 (暂未使用)
agile.security.password.offset=3612213421341234
# 密码传输算法模式 (暂未使用)
agile.security.password.algorithm-model=AES/CBC/PKCS5Padding

# 密码强度检测配置
# 密码强度关键字匹配策略
agile.security.password.strength-conf.weight-of-key-words=password,iloveyou,sunshine,1314,520,a1b2c3,admin
# 密码强度关键字匹配策略整体权重
agile.security.password.strength-conf.weight-of-key-word=0.35
# 密码强度正则匹配策略及权重
agile.security.password.strength-conf.weight-of-regex-map[0].regex=(?:([\\da-zA-Z])\\1{2,})
agile.security.password.strength-conf.weight-of-regex-map[0].weight=0.4
agile.security.password.strength-conf.weight-of-regex-map[1].regex=(?:([\\da-zA-Z])\\1+){2,}
agile.security.password.strength-conf.weight-of-regex-map[1].weight=0.15
agile.security.password.strength-conf.weight-of-regex-map[2].regex=([\\da-zA-Z]{2,})\\1+
agile.security.password.strength-conf.weight-of-regex-map[2].weight=0.12
agile.security.password.strength-conf.weight-of-regex-map[3].regex=((?:0(?=1)|1(?=2)|2(?=3)|3(?=4)|4(?=5)|5(?=6)|6(?=7)|7(?=8)|8(?=9)){2,}+\\d)|((?:9(?=8)|8(?=7)|7(?=6)|6(?=5)|5(?=4)|4(?=3)|3(?=2)|2(?=1)|1(?=0)){2,}+\\d)
agile.security.password.strength-conf.weight-of-regex-map[3].weight=0.2
agile.security.password.strength-conf.weight-of-regex-map[4].regex=((?:a(?=b)|b(?=c)|c(?=d)|d(?=e)|e(?=f)|f(?=g)|g(?=h)|h(?=i)|i(?=j)|j(?=k)|k(?=l)|l(?=m)|m(?=n)|n(?=o)|o(?=p)|p(?=q)|q(?=r)|r(?=s)|s(?=t)|t(?=u)|u(?=v)|v(?=w)|w(?=x)|x(?=y)|y(?=z)){2,}+[a-z])|((?:A(?=B)|B(?=C)|C(?=D)|D(?=E)|E(?=F)|F(?=G)|G(?=H)|H(?=I)|I(?=J)|J(?=K)|K(?=L)|L(?=M)|M(?=N)|N(?=O)|O(?=P)|P(?=Q)|Q(?=R)|R(?=S)|S(?=T)|T(?=U)|U(?=V)|V(?=W)|W(?=X)|X(?=Y)|Y(?=Z)){2,}+[A-Z])
agile.security.password.strength-conf.weight-of-regex-map[4].weight=0.18
agile.security.password.strength-conf.weight-of-regex-map[5].regex=((?:q(?=w)|w(?=e)|e(?=r)|r(?=t)|t(?=y)|y(?=u)|u(?=i)|i(?=o)|o(?=p)){2,}+[a-z])|((?:Q(?=W)|W(?=E)|E(?=R)|R(?=T)|T(?=Y)|Y(?=U)|U(?=I)|I(?=O)|O(?=P)){2,}+[A-Z])|((?:a(?=s)|s(?=d)|d(?=f)|f(?=g)|g(?=h)|h(?=j)|j(?=k)|k(?=l)){2,}+[a-z])|((?:A(?=S)|S(?=D)|D(?=F)|F(?=G)|G(?=H)|H(?=J)|J(?=K)|K(?=L)){2,}+[A-Z])|((?:z(?=x)|x(?=c)|c(?=v)|v(?=b)|b(?=n)|n(?=m)){2,}+[a-z])|((?:Z(?=X)|X(?=C)|C(?=V)|V(?=B)|B(?=N)|N(?=M)){2,}+[A-Z])
agile.security.password.strength-conf.weight-of-regex-map[5].weight=0.1
agile.security.password.strength-conf.weight-of-regex-map[6].regex=((((19|20)\\d{2})-(0?[13-9]|1[012])-(0?[1-9]|[12]\\d|30))|(((19|20)\\d{2})-(0?[13578]|1[02])-31)|(((19|20)\\d{2})-0?2-(0?[1-9]|1\\d|2[0-8]))|((((19|20)([13579][26]|[2468][048]|0[48]))|(2000))-0?2-29))
agile.security.password.strength-conf.weight-of-regex-map[6].weight=0.3
# 密码强度正则匹配策略整体权重
agile.security.password.strength-conf.weight-of-regex=0.65
# 长度策略权重最大得分
agile.security.password.strength-conf.max-length=32

# 登录失败限制配置
# 登录失败限制开关
agile.security.error-sign.enable=true
# 过期是否锁定 (暂未使用)
agile.security.error-sign.lock-for-expiration=true
# 最大失败次数,超过此次数后的登录行为将触发限制登录
agile.security.error-sign.max-error-count=5
# 限制登录时间
agile.security.error-sign.lock-time=3m
# 登录失败计数器间隔
agile.security.error-sign.count-timeout=1m
# 登录失败限制对象,ip(客户端ip)、account(登录帐号)、session_id(浏览器会话标识),可结合使用,以限制同ip下同账户同浏览器会话限制为例
agile.security.error-sign.lock-type=account,ip,session_id

# 认证组件结果处理请求转发地址
# 登录失败、权限验证失败转发地址
agile.security.fail-forward-url=/fail
# 登录成功转发地址
agile.security.success-forward-url=/success
# 退出成功地址
agile.security.success-logout-forward-url=/logout-success

# 模拟账号
# 模拟账号json数据
agile.simulation.user={"username":"admin2","password":"$2a$04$H5Zj6JmtZRyyrVKKMsJmO.txNXcRQNWxo5C.d0KoijnlqCbGdi0fq","enabled":true,"accountNonExpired":true,"accountNonLocked":false,"credentialsNonExpired":true,"authorities":[],"loginStrategy":"MORE"}
# 模拟账号信息映射java类型
agile.simulation.user-class=cloud.agileframework.security.filter.login.InMemoryUserDetails
# 模拟开关
agile.simulation.enable=false

# 验证码,其余验证码配置请参考https://github.com/mydeathtrial/spring-boot-starter-kaptcha
# 验证码组件开关
agile.kaptcha.enable=false
# 验证码地址
agile.kaptcha.url=/code

深度定制

定制持久化方式
以JPA类框架为例,帐号信息的ORM映射类需要符合cloud.agileframework.security.filter.login.CustomerUserDetails接口,接口中约束了账户信息必要的帐号、密码、权限集等信息。
持久层化操作工具(如xxxService)应符合cloud.agileframework.security.filter.login.CustomerUserDetailsService接口,接口中约束账户信息持久化操作的必要方法,如创建、
更新、删除、判断、加载等等持久化能力。

组件中内置了以内存方式持久化的实现方式,可以直接参考以下源码:
账户信息:cloud.agileframework.security.filter.login.InMemoryUserDetails
持久化能力:cloud.agileframework.security.filter.login.InMemoryUserDetailsServiceImpl
定制化登录验证
自定义验证提供者应该遵循接口cloud.agileframework.security.provider.LoginValidateProvider,组件将在登录事件发生时调用登录验证提供者提供的验证能力。组件
内置了表单完整度(CompleteFormLoginValidateProvider)、失败限制(ErrorSignLockLoginValidateProvider)、验证码(KaptchaLoginValidateProvider)、
登录策略(LoginStrategyLoginValidateProvider)四种登录验证提供者

以表单完整度为例,将其注入到spring容器,组件即可识别:
public class CompleteFormLoginValidateProvider implements LoginValidateProvider {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public void validate(HttpServletRequest request, HttpServletResponse response, String username, String password) throws AuthenticationException {
        // 验证表单完整性
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            throw new NoCompleteFormSign();
        }
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("正在登陆...[账号:%s][密码:%s]", username, password));
        }
    }
}
定制化密码密文传输
定制密码密文传输解密提供者,需要遵循接口cloud.agileframework.security.provider.PasswordProvider
组件会在登录验证之前调用定制密码密文传输解密提供者,解密密码。
/**
 * @author Mydeathtrial
 * 描述 密码解密,用于前后端密文传输扩展使用
 * @version 1.0
 * @since 1.0
 */
public interface PasswordProvider {
    /**
     * 解密
     *
     * @param ciphertext 密文
     * @return 明文
     */
    String decrypt(String ciphertext);
}
定制账号退出钩子函数
帐号退出钩子函数需要遵循接口cloud.agileframework.security.provider.LogoutProcessorProvider
组件会在产生帐号登出时触发该函数,应用场景很多,如切断指定帐号的websocket。
/**
 * @author Mydeathtrial
 * 描述 帐号退出以后调用
 * @version 1.0
 * @since 1.0
 */
public interface LogoutProcessorProvider {
    /**
     * 退出之后
     *
     * @param username 帐号
     * @param token    身份令牌
     */
    void after(String username, String token);
}
定制认证处理结果响应报文
定制化结果响应报文,需要遵循接口cloud.agileframework.security.provider.SecurityResultProvider
其中包含三种结果处理能力,其中accessException较为特殊,提供了认证异常的种类,默认处理形式是直接将异常抛出
以此方式将异常交给如@ControllerAdvice等统一异常处理器处理结果视图
/**
 * @author Mydeathtrial
 * 描述 认证结果处理,用于订制响应认证成功/失败/退出等响应信息
 * @version 1.0
 * @since 1.0
 */
public interface SecurityResultProvider {
    /**
     * 认证失败处理
     *
     * @param request  请求
     * @param response 响应
     * @param e        异常
     * @return 响应视图,默认会将异常抛出,供统一异常处理器处理响应
     * @throws Throwable 异常
     */
    default Object accessException(HttpServletRequest request, HttpServletResponse response, Throwable e) throws Throwable {
        throw e;
    }

    /**
     * 登陆成功处理
     *
     * @param request        请求
     * @param response       响应
     * @param authentication 认证成功后的权限数据,其中包含账号信息、令牌信息、权限集合信息
     * @return 响应视图
     */
    default Object loginSuccess(HttpServletRequest request, HttpServletResponse response, UsernamePasswordAuthenticationToken authentication) {
        return authentication;
    }

    /**
     * 退出成功
     *
     * @param request  请求
     * @param response 响应
     * @param username 帐号
     * @param token    令牌
     * @return 响应视图
     */
    default Object logoutSuccess(HttpServletRequest request, HttpServletResponse response, String username, String token) {
        ModelAndView modelAndView = new ModelAndView(new MappingJackson2JsonView());
        modelAndView.addObject("username", username);
        modelAndView.addObject("token", token);
        return modelAndView;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值