背景

今天讲下若依框架对于登录认证方面的实现,这个方面若依做的不算太好,如果项目中想用的话需要参考其他框架的实现,做的更好一些。

我建议是前后端放在一起来看,单纯看后端会比较无趣。

后端部分

/login 接口

  • userName
  • password
  • code 验证码

前端获取上面三个要素后调用接口,整体改接口做了下面几件事情

  1. 验证用户身份(账号密码+验证码)
  2. 生成token
  3. 保存用户登录态到spring security中
安全配置:定义了基本的配置信息
framework.config.SecurityConfig

UserDetailsServiceImpl 用户验证处理类

登录接口的服务类
framework.web.service.SysLoginService

JWT拦截器,拦截令牌并校验信息
framework.security.filter.JwtAuthenticationTokenFilter

详细过程

  1. SysLoginService 中调用UserDetailsServiceImpl校验用户的密码是否匹配以及用户账户状态,校验通过后返回UserDetails实例,该实例包含了用户的基本信息和菜单权限信息
  2. 调用tokenService.createToken(loginUser)生成token

令牌生成的详细过程

  1. 生成uuid随机数,这个随机数用来做rediskey存储token
  2. 生成一个token(无时效)
  3. 拦截到的token如果距离失效在10分钟以内(可配置)就自动刷新有效期

前面提到了token本身无时效,有效期是通过redis控制的,因为jwt本身未提供刷新有效期的方法(可能是我不知道)。

以上用户调用了login接口并且获得了token

jwt令牌校验

/**
 * token过滤器 验证token有效性
 * 
 * @author sj
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
{
    @Autowired
    private TokenService tokenService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException
    {
        LoginUser loginUser = tokenService.getLoginUser(request);
        if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication()))
        {
            tokenService.verifyToken(loginUser);
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        }
        chain.doFilter(request, response);
    }
}

代码比较短,所以就直接贴出来,这段代码拦截了所有请求并且完成了令牌的校验和刷新,具体过程如下

  1. tokenService.getLoginUser(request); 从request中获取token并校验,如果校验通过就返回LoginUser对象
  2. 校验LoginUser的token,如果再刷限期内就直接刷新
  3. 将LoginUser封装到SecurityContextHolder中作为全局的用户登录状态

注:第3条有两个好处

  1. 后续拦截器发现SecurityContextHolder中保存了用户时,就直接通过校验
  2. 通过SecurityContextHolder可以快速获取当前请求的登录信息。

以上基本上已经说名了JWT校验的基本过程,忽略了很多细节,基础薄弱的同学可以需要先研究其他博客再来看这篇

getInfo 获取用户信息

  1. 用户的基本信息
  2. 用户所有的Permissions(菜单树)
  3. 用户所有的RopePersmission(roleKeys)

若依框架日志系统 若依框架登录_用户登录

getRouters 获取前端页面路由信息

这个接口完全为前端准备,后面会专门讲述前端的权限控制

若依框架日志系统 若依框架登录_用户登录_02