SurenessSecurityManager securityManager = SurenessSecurityManager.getInstance();
SurenessSecurityManager中的静态常量每次创建是单例的
private static final SurenessSecurityManager INSTANCE = new SurenessSecurityManager();
@Override
public List<Subject> createSubject(Object var1) {
return subjectFactory.createSubjects(var1);
}
所有subjectCreate
在初始化的时候,在factory中将5个creator传入,也可以自定义creator
如果是jwt则会获取JwtSubjectServletCreator
CustomTokenSubjectCreator request应为{“Token” : “tokenValue”}的形式
(String token = account.getUsername() + “–” + System.currentTimeMillis()
+ “–” + refreshPeriodTime
+ “–”+ UUID.randomUUID().toString().replace("-", “”);)
经过filter得到所支持的creator
经过map得到subject,在经过filter过滤掉空的subject,剩下jwtsubject和nonesubject
在验证是否是过滤的路径,添加支持的角色,通过processmananger.process()按subject类型遍历合适的processor在认证和授权然后将subject包装成SubjectSum
JwtProcessor来验证jwtsubject
验证jwt重新build新的jwtsubject(没有jwt)
所有的processor(PasswordProcessor需要额外提供以个SurenessAccountProvider,通过appid查找相应的用户信息)
provider 获取数据源
所有的Provider
利用snakeyaml解析yml文件
provider中loadaccount实现方法按照addid从配置文件中查找相应的信息
分析jwt认证
1.发送请求拦截器会进行判断由于是排除的url会直接访问,选择需要的provider,使用documentAccountprovider时,输入appid和password从yaml中查找account信息进行authentication,如果成功则返回jwt
2.当其他没有被排除的请求发送过来时,如果header有authentication的话找到相应的creator获得subject
在经过processor处理授权和认证(jwt解码认证和过期认证等等都在这里)把subject变成subjectsum
3.如果认证和授权成功则放行,访问相应的url,如果失败则会抛出异常,直到抛到intercptor中被捕捉,然后信息放到返回体中。
另外
// 认证鉴权成功则会返回带用户信息的subject 可以将subject信息绑定到当前线程上下文holder供后面使用
if (subject != null) {
SurenessContextHolder.bindSubject(subject)
log.debug("auth success!")
}
//使用 上下文获得当前登陆用户的信息(principa,roles,所请求的资源)
val subject = SurenessContextHolder.getBindSubject()
在ktor中的使用
post("/api/v1/account/auth") {
val receiveParameters = call.receive<Map<String, String>>()
if (!receiveParameters.containsKey("appId") || !receiveParameters.containsKey("password")) {
call.respond(HttpStatusCode.BadRequest)
return@post finish()
}
val accountProvider = DocumentAccountProvider()
val appId = receiveParameters["appId"]
var password = receiveParameters["password"]
val account = accountProvider.loadAccount(appId)
if (account == null || account.isDisabledAccount || account.isExcessiveAttempts) {
call.respond(HttpStatusCode.Forbidden)
return@post finish()
}
if (account.password != null) {
if (account.salt != null) {
password = Md5Util.md5(password + account.salt)
}
if (account.password != password) {
call.respond(HttpStatusCode.Forbidden)
return@post finish()
}
}
// Get the roles the user has - rbac
val roles = account.ownRoles
// issue jwt
val jwt = JsonWebTokenUtil.issueJwt(
randomUUID().toString(), appId,
"token-server", 3600, roles
)
val body = Collections.singletonMap("token", jwt)
call.respond(HttpStatusCode.OK,body)
}