目的
需要在Flowable框架下实现获取当前授权用户ID以及实现接口访问授权,由于Flowable是基于spring security的,考虑基于此实现。spring security原生的授权过程为:
1.构造token
UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(uid, pwd);
2.构造auth(继承了principal)
org.springframework.security.core.Authentication auth = authManager.authenticate(authReq);
3.向context传入auth对象
SecurityContext sc = SecurityContextHolder.getContext();
sc.setAuthentication(auth);
Flowable设置授权用户的方法为
Authentication.setAuthenticationContext(sc);
Authentication.setAuthenticatedUserId();
-------以下是源代码
public static void setAuthenticationContext(AuthenticationContext authenticationContext) {
Authentication.authenticationContext = authenticationContext;
}
需要将二者结合并尽可能复用代码。
源代码分析
在setAuthenticatedUserId方法中,会先向context设置principal,一般来说就是直接new一个UserIdPrincipal喂给context的setprincipal方法,而这个setprincipal的过程就是封装了spring security的context操作,
public static void setAuthenticatedUserId(String authenticatedUserId) {
authenticationContext.setPrincipal(authenticatedUserId == null ? null : new UserIdPrincipal(authenticatedUserId));
}
public void setPrincipal(Principal principal) {
if (principal == null) {
SecurityContextHolder.getContext().setAuthentication((Authentication)null);
} else if (principal instanceof Authentication) {
SecurityContextHolder.getContext().setAuthentication((Authentication)principal);
} else {
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(principal, (Object)null));
LOGGER.debug("Setting a principal that is not of type `org.springframework.security.core.Authentication`. When using Spring Security you can just set the user through 'SecurityContextHolder.getContext().setAuthentication(..)' Using 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken' to wrap the principal of type '{}'", principal.getClass());
}
}
第一节的使用方法是走第二个分支。
这里可以发现,Flowable没有对用户进行授权的关键在于,setAuthentication方法所传入的principal没有认证信息,因此考虑外部手动构建context并投喂给正确的principal
最终代码如下:
UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(uid, pwd);
org.springframework.security.core.Authentication auth = authManager.authenticate(authReq);
SpringSecurityAuthenticationContext sc = new SpringSecurityAuthenticationContext();
sc.setPrincipal(auth);
Authentication.setAuthenticationContext(sc);
Flowable可以接收两种context:UserIdAuthenticationContext与SpringSecurityAuthenticationContext,这里应当使用后者
public class UserIdAuthenticationContext implements AuthenticationContext {
private static ThreadLocal<Principal> authenticatedUserIdThreadLocal = new ThreadLocal();
---------------------------------------
final class ThreadLocalSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
private static final ThreadLocal<SecurityContext> contextHolder = new ThreadLocal();
虽然二者都基于threadlocal,但对比二者的底层实现可知后者才是单例模式
网友评论