鉴权

ACE项目是一个比较完整的使用了spring cloud框架的开源项目,可以用它来快速搭建分布式系统。本次着重看的部分是其服务以及用户鉴权的部分。ACE有一个鉴权服务,负责微服务群的鉴权。启动ACE项目依次启动center,auth-server,admin,gateway即可。

模块架构

鉴权模块分为服务端和客户端(另有一个common模块,可忽略,是一些鉴权模块公用代码的提取)。应用程序依赖客户端,客户端提供了两个拦截器,工具类,并和服务端通信的feign。服务端则负责token生成,验证和更新。

代码分析

程序启动

auth-server启动时初始化KeyConfiguration,获得userSecret和serviceSecret.并在启动结束的钩子类AuthServerRunner中,分别设置User和Server的pri/puk.User用于用户认证,Server用于微服务认证。

admin和gateway在启动的时候,会调用auth-client的自动配置,生成ServiceAuthConfig和UserAuthConfig的实例。同时auth-client的AuthClientRunner会请求pubkey到ServiceAuthConfig和UserAuthConfig的实例。同时在应用各自的WebConfiguration中添加UserAuthRestInterceptor和ServiceAuthRestInterceptor拦截器

运行阶段

用户认证,由UserAuthRestInterceptor处理。
在用户登录的时候,调用jwtTokenUtil.generateToken生成token。这个token的生成规则稍后再论。在浏览器记录一个Admin-Token.

--auth-server
public String login(JwtAuthenticationRequest authenticationRequest) throws Exception {
        UserInfo info = userService.validate(authenticationRequest);
        if (!StringUtils.isEmpty(info.getId())) {
            return jwtTokenUtil.generateToken(new JWTInfo(info.getUsername(), info.getId() + "", info.getName()));
        }
        throw new UserInvalidException("用户不存在或账户密码错误!");
}

登录之后的请求都会经过UserAuthRestInterceptor,在解析token的时候同时会进行过期,签名合法等验证。并把这些信息加到threadLocal中去。

--UserAuthRestInterceptor
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        ......
        IJWTInfo infoFromToken = userAuthUtil.getInfoFromToken(token);
        BaseContextHandler.setUsername(infoFromToken.getUniqueName());
        BaseContextHandler.setName(infoFromToken.getName());
        BaseContextHandler.setUserID(infoFromToken.getId());
        return super.preHandle(request, response, handler);
}
    
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        BaseContextHandler.remove();
        super.afterCompletion(request, response, handler, ex);
}

服务认证由ServiceAuthRestInterceptor处理。service的鉴权也是通过user的token。通过serviceAuthConfig.getTokenHeader()来解析service的信息。

--ServiceAuthRestInterceptor
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       ......
        String token = request.getHeader(serviceAuthConfig.getTokenHeader());
        IJWTInfo infoFromToken = serviceAuthUtil.getInfoFromToken(token);
        String uniqueName = infoFromToken.getUniqueName();
        for(String client:serviceAuthUtil.getAllowedClient()){
            if(client.equals(uniqueName)){
                return super.preHandle(request, response, handler);
            }
        }
        throw new ClientForbiddenException("Client is Forbidden!");
}

一些方法解读(待补充)

jwtTokenUtil.generateToken:生成用户token
userService.validate:验证用户的合法性
userAuthUtil.getInfoFromToken(token):从token中获得用户名称和ID等信息。


沈子平
183 声望17 粉丝

慢慢积累,一切都不会太晚.