A simple and efficient open-source jvm security framework that focus on the protection of restful api.
若主页usthe.com/sureness 访问不了,请使用备用网站: su.usthe.com
现在很多网站都进行了前后端分离,后端提供rest api,前端调用接口获取数据渲染。这种架构下如何保护好后端所提供的rest api使得更加重视。
api的保护可以认为:认证-请求携带的认证信息是否校验通过,鉴权-认证通过的用户拥有指定api的权限才能访问此api。然而不仅于此,什么样的认证策略, jwt, basic,digest,oauth还是多支持, 权限配置是写死代码还是动态配置,我想动态赋权怎么办,云原生越来越火用的框架是quarkus等新秀不是spring生态咋弄,http实现不是servlet而是jax-rs规范咋整, to be or not to be, this is a question
目前
java
主流的权限框架有shiro,spring security
, 下面对于它们的探讨都是个人之见,接受纠正
shiro
对于restful api
原生支持不太友好,需要改写一些代码,2年前一个项目 booshiro 就是改造shiro
,使其在过滤链就能匹配不同的rest
请求进行权限校验,之后给shiro commit
几次pr
,fix
其在过滤链匹配时的危险漏洞,总的来说shiro
很强大但其起源并非面向web
,对restful
不是很友好
spring security
很强大,与spring
深度集成,离开spring
,比如javalin
和之前用过的osgi
框架karaf
就用不了了
如果不用注解配置,它们都会在链式匹配这块,用请求的url和配置的链一个一个ant
匹配(匹配过程中会有缓存等提高性能),但匹配的链过多时还是比较耗性能(根据算法时间复杂度判断,暂未测试验证)
我们希望能解决这些,提供一个针对restful api,无框架依赖,可以动态修改权限,多认证策略,更快速度,易用的认证鉴权框架
sureness
是我们在使用java
权限框架shiro
之后,吸取其良好设计加上一些想法实现的全新认证鉴权项目
面对restful api
的认证鉴权,基于rbac
(用户-角色-资源)主要关注于对restful api
的安全保护
无特定框架依赖(本质就是过滤器处拦截判断,已有springboot,quarkus,javalin,ktor等demo)
支持动态修改权限配置(动态修改哪些api需要被认证,可以被谁访问)
支持主流http容器 servlet 和 jax-rs
支持多种认证策略,jwt, basic auth, digest auth
... 可扩展自定义支持的认证方式
基于改进的字典匹配树拥有的高性能
良好的扩展接口, demo和文档
sureness
的低配置,易扩展,不耦合其他框架,能使开发者对自己的项目多场景快速安全的进行保护
- spring sample-bootstrap
- springboot sample-tom
- quarkus sample-quarkus
- javalin sample-javalin
- ktor sample-ktor
- spring webflux sample-spring-webflux
- more samples todo
sureness
尽量简洁,基于rbac
,只有(角色-资源)的映射,没有(权限)动作映射,即 用户-角色-资源- 我们将
restful api
请求视作一个资源,资源格式为:requestUri===httpMethod
即请求的路径加上其请求方式(post,get,put,delete...
)作为一个整体被视作一个资源
eg: /api/v2/book===get
get
方式请求/api/v2/book
接口数据 - 角色资源映射: 用户所属角色--角色拥有资源--用户拥有资源(用户就能访问此
api
)
资源路径匹配详见 url路径匹配
项目使用maven
或gradle
构建,加入坐标
<dependency>
<groupId>com.usthe.sureness</groupId>
<artifactId>sureness-core</artifactId>
<version>0.4</version>
</dependency>
compile group: 'com.usthe.sureness', name: 'sureness-core', version: '0.4'
默认配置使用了文件数据源sureness.yml作为账户权限数据源
默认配置支持了jwt, basic auth, digest auth认证
@Bean
public DefaultSurenessConfig surenessConfig() {
return new DefaultSurenessConfig();
}
sureness
认证鉴权,当然也需要我们提供自己的账户数据,角色权限数据等,这些数据可能来自文本,关系数据库,非关系数据库,注解等。
我们提供了数据源接口:SurenessAccountProvider
- 账户数据接口, PathTreeProvider
- 资源权限数据接口,用户可以实现此接口实现自定义数据源。
当前我们也提供文本形式的数据源实现 DocumentResourceDefaultProvider
和 注解形式的资源权限数据源实现 AnnotationLoader
。
如果是使用了默认sureness配置-DefaultSurenessConfig,其配置的是文本数据源,用户可以直接通过修改sureness.yml
文件来配置数据。
文本数据源sureness.yml
配置使用方式详见文档 默认文本数据源
注解形式的资源权限数据源配置使用方式详见文档 注解资源权限数据源
我们提供了使用代码DEMO
:
默认文本数据源具体实现,请参考使用sureness10分钟搭建权限项目--sample-bootstrap
若权限配置数据来自数据库,请参考使用sureness30分钟搭建权限项目--sample-tom
sureness
的本质就拦截所有rest请求对其认证鉴权判断。
入口拦截器器实现一般可以是 filter or spring interceptor
在拦截器中加入sureness
的安全过滤器,如下:
SubjectSum subject = SurenessSecurityManager.getInstance().checkIn(servletRequest)
sureness
使用异常处理流程:
- 若认证鉴权成功,
checkIn
会返回包含用户信息的SubjectSum
对象 - 若中间认证鉴权失败,
checkIn
会抛出不同类型的认证鉴权异常,用户需根据这些异常来继续后面的流程(返回相应的请求响应)
这里我们就需要对checkIn
抛出的异常做自定义处理,认证鉴权成功直接通过,失败抛出特定异常进行处理,如下:
try {
SubjectSum subject = SurenessSecurityManager.getInstance().checkIn(servletRequest);
} catch (ProcessorNotFoundException | UnknownAccountException | UnsupportedSubjectException e4) {
// 账户创建相关异常
} catch (DisabledAccountException | ExcessiveAttemptsException e2 ) {
// 账户禁用相关异常
} catch (IncorrectCredentialsException | ExpiredCredentialsException e3) {
// 认证失败相关异常
} catch (UnauthorizedException e5) {
// 鉴权失败相关异常
} catch (SurenessAuthenticationException | SurenessAuthorizationException e) {
// 其他自定义异常
}
异常详见 默认异常类型
HAVE FUN
如果了解 处理流程,就大概知道sureness
提供的扩展点
sureness
支持自定义subject
,自定义subjectCreator
注册,自定义processor
处理器等
扩展之前需要了解以下接口:
Subject
: 认证鉴权对象接口,提供访问对象的账户密钥,请求资源,角色等信息SubjectCreate
: 创建Subject
接口,根据请求内容创建不同类型的Subject
对象Processor
:Subject
处理接口,根据Subject信息,进行认证鉴权PathTreeProvider
: 资源的数据源接口,实现从数据库,文本等加载数据SurenessAccountProvider
: 用户的账户密钥信息接口,实现从数据库,文本等加载数据
sureness
大致流程:
- 自定义数据源
实现 PathTreeProvider
的接口, 加载到DefaultPathRoleMatcher
中
实现 SurenessAccountProvider
的接口,加载到需要的processor
中
- 自定义subject
实现Subject
接口,添加自定义的subject
内容
实现SubjectCreate
接口方法,创建出自定义的subject
实现Processor
接口,支持处理自定义的subject
- 自定义processor
一个subject
当然也可以被不同的processor
处理,所以可以单独自定义processor
实现Processor
接口,设置支持的subject
,实现处理该subject
的逻辑
具体扩展实践请参考 使用sureness30分钟搭建权限项目--sample-tom
非常欢迎参与项目贡献,跟sureness一起走得更远更好。对项目代码有疑问或者建议请直接联系 @tomsun28
仓库的组成部分: