token前置校验,登入后获取用户详细信息

758 阅读3分钟

token前置校验

若依后台管理token前置校验使用一个全局过滤器实现,具体类在com.ruoyi.framework.security.filter下

具体代码

@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 获取用户登入对象

2 如果登入对象存在且spring security域对象内为空说明请求是首次被过滤器拦截且用户是登入状态。

3 判断成功,刷新token,将loginUser 对象封装成authentication对象并且存入spring security域对象之中,可以让后面的控制器都能访问,然后放行。

4 放行

具体实现

代码中可以看到,通过调用tokenService实现类的getLoginUser方法可以实现登入对象的获取。点开方法

public LoginUser getLoginUser(HttpServletRequest request)
{
    // 获取请求携带的令牌
    String token = getToken(request);
    if (StringUtils.isNotEmpty(token))
    {
        try
        {
            Claims claims = parseToken(token);
            // 解析对应的权限以及用户信息
            String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
            String userKey = getTokenKey(uuid);
            LoginUser user = redisCache.getCacheObject(userKey);
            return user;
        }
        catch (Exception e)
        {
        }
    }
    return null;
}

此方法接收HttpServletRequest对象为参数,从中取出token,token为空返回null,不为空则解析token拿取负载获取key值,去redis查找之前登入存入的loginUser对象然后返回。

登入后获取用户信息

请求地址

http://localhost/dev-api/getInfo

返回数据

image.png 主要是用户权限集,角色集,用户信息

控制器在 com.ruoyi.web.controller.system下;

主要代码

@GetMapping("getInfo")
public AjaxResult getInfo()
{
    SysUser user = SecurityUtils.getLoginUser().getUser();
    // 角色集合
    Set<String> roles = permissionService.getRolePermission(user);
    // 权限集合
    Set<String> permissions = permissionService.getMenuPermission(user);
    AjaxResult ajax = AjaxResult.success();
    ajax.put("user", user);
    ajax.put("roles", roles);
    ajax.put("permissions", permissions);
    return ajax;
}

业务流程

1 获取当前用户对象

2 获取用户角色集合(sys_role表下的role_key字段)

3 获取用户的权限集合(sys_menu表下的perms)

4 返回数据

具体实现

1 SecurityUtils.getLoginUser().getUser() 此函数用于获取spring security 域对象内的loginUser对象,如果用户是登入状态,则可以获取该对象,反之则为null

2 若依关于用户权限的五张表 sys_user(用户表),sys_user_role(用户与角色关联表),sys_role(角色表),sys_role_menu(角色与菜单关联表),sys_menu(菜单表)

image.png

image.png

image.png

image.png

image.png

通过链接sys_user,sys_user_role,sys_role三张表可以查出每个用户对应的角色,对应sql语句为

select sr.role_key from (sys_user su left join sys_user_role sur on su.user_id=sur.user_id) left join sys_role sr on sur.role_id=sr.role_id where su.user_id=?

参数为我们传递进去的用户id

通过链接sys_role,sys_role_menu,sys_menu三张表可以查出每个角色对应的权限

select sm.perms from (sys_role sr left join sys_role_menu srm on sr.role_id=srm.role_id) left join sys_menu sm on srm.menu_id=sm.menu_id where sr.role_id=? 参数为角色id

通过链接sys_user,sys_user_role,sys_role_menu,sys_menu,可以查出每个用户对应的权限

select sm.perms from (sys_user su left join sys_user_role sur on su.user_id=sur.user_id left join sys_role_menu srm on sur.role_id=srm.role_id) left join sys_menu sm on srm.menu_id=sm.menu_id where su.user_id=? 参数为用户id

如果查询的用户是管理员角色,这里返回为null,因为在sys_role_menu中没有说明管理员角色对应的权限id, 那是如何实现管理员拥有所有权限的功能呢,点开getMenuPermission函数,

image.png

public Set<String> getMenuPermission(SysUser user)
{
    Set<String> perms = new HashSet<String>();
    // 管理员拥有所有权限
    if (user.isAdmin())
    {
        perms.add("*:*:*");
    }
    else
    {
        List<SysRole> roles = user.getRoles();
        if (!roles.isEmpty() && roles.size() > 1)
        {
            // 多角色设置permissions属性,以便数据权限匹配权限
            for (SysRole role : roles)
            {
                Set<String> rolePerms = menuService.selectMenuPermsByRoleId(role.getRoleId());
                role.setPermissions(rolePerms);
                perms.addAll(rolePerms);
            }
        }
        else
        {
            perms.addAll(menuService.selectMenuPermsByUserId(user.getUserId()));
        }
    }
    return perms;
}

可以看到在判断到该用户是管理员后手动给该用户添加所有权限,不会通过数据库查询权限。

用户和角色是一对多关系,角色和权限也是一对多关系,所以一个用户有多个权限多个角色