若依框架后端登录流程
若依框架前后端分离 项目(前端vue,后端 springboot)。
这里只记录后端springboot。
验证码:
用户进入登录页,请求 /captchaImage 接口获取验证码:



登录
用户点击登录,前端会把如下参数传给后端

登录接口 /login
(0)最终目的:获取token,前端带着token请求 接口。
(1)大致流程:
验证验证码是否正确(过期、输出错误) -> 调用security api来进行用户验证,这里会根据username来查询数据库,判断是否有这个用户,如果有这个用户,接着判断是否是超管(如果是超管,就不会去查询对应的菜单权限;不是超管,会根据userId查询数据库,来获取对应的菜单权限),然后把对应的信息填充在 LoginUser类中,security中,也会记录当前登录的用户信息 -> 最后,更新用户登录ip、时间,然后生成token,返给前端。
(2)详细流程:
登录接口 /login

loginService中的login方法:
下边是security 的api了,也是重点:
authenticationManager.authenticate() 是security内部api,web登录时,内部会调用 authenticationManager.authenticate()对账号和密码做验证,具体细节不做介绍。最终security会调用UserDetailsServiceImpl.loadUserByUsername(String username) 方法,而若依重写了此方法:

在ruoyi-framework中,重点(重写此方法需要实现UserDetailsService接口),重写了loadUserByUsername:

根据username查询数据库,一堆if判断用户状态

如果有该用户,会调用createLoginUser() 方法来返回 LoginUser 类,为什么会返回LoginUser ,因为: LoginUser 实现了 UserDetails 接口。

getMenuPermission() 方法:

LoginUser类,查询出用户信息,会填充在LoginUser中:


接着,菜单权限查询成功, 会异步打印日志,然后更新用户登录ip,日期。


最后,生成token,返给前端:


获取用户信息 /getInfo
如果前端登录请求顺利,接着会进入后台首页,在这之前,路由守卫中,还会判断vuex中是否有角色的key(我的理解就是一个角色标识),如果没有,会请求/getInfo 接口:
下边两个角色查询和权限查询 都是根据用户id来查询的:

角色查询,其实跟登录时的菜单权限查询类似,都是先判断是否是超管,不是回去查询数据库:

权限查询,跟角色查询一样:

没问题,直接返回给前端,数据如下:

前端会把相关信息存到vuex中:

获取路由信息及按钮信息 /getRouters
用户信息请求成功后,会在成功的回调中(路由守卫里边)请求路由、按钮的相关信息,

的对应接口: /getRouters
先看下根据userId 获取菜单树,


getChildPerms() 方法会构建父子级关系(注意这个方法还不是构建前端路由列表),具体,如何递归的自己看源码吧
构建完父子级关系, List

最后,构建前端需要的路由树,buildMnus() 方法,要理解这个方法,必须对前台相当了解才行!

设置路由的相关信息,可结合前台页面,添加菜单中的选项:
/*** 构建前端路由所需要的菜单* * @param menus 菜单列表* @return 路由列表*/
@Override
public List buildMenus(List menus)
{List routers = new LinkedList();for (SysMenu menu : menus){// 路由的相关信息RouterVo router = new RouterVo();// 0 路由是否显示,1 不显示 -> hidden: true/falserouter.setHidden("1".equals(menu.getVisible()));// 设置路由name,且会把name首字母大写 -> name: "name"router.setName(getRouteName(menu));// 设置路由访问路径 -> path: "/path"router.setPath(getRouterPath(menu));// 设置组件router.setComponent(getComponent(menu));// 设置meta信息router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));// 设置Children,如果有的话,子组件默认都是显示的 且 不重定向的。接着递归去设置子组件的一些属性值List cMenus = menu.getChildren();// 【目录】 如:前端 系统管理if (!cMenus.isEmpty() && cMenus.size() > 0 && UserConstants.TYPE_DIR.equals(menu.getMenuType())){router.setAlwaysShow(true);router.setRedirect("noRedirect");router.setChildren(buildMenus(cMenus)); // 递归设置子组件的属性}// 【是否是内连接的菜单且没有父级(对应前端页面比如:首页)】else if (isMenuFrame(menu)){// 下边这些跟上边一样了router.setMeta(null);List childrenList = new ArrayList();RouterVo children = new RouterVo();children.setPath(menu.getPath());children.setComponent(menu.getComponent());children.setName(StringUtils.capitalize(menu.getPath()));children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));childrenList.add(children);router.setChildren(childrenList);}// ???????? 是否为内链组件 ????????else if (menu.getParentId().intValue() == 0 && isInnerLink(menu)){router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));router.setPath("/inner");List childrenList = new ArrayList();RouterVo children = new RouterVo();String routerPath = StringUtils.replaceEach(menu.getPath(), new String[] { Constants.HTTP, Constants.HTTPS }, new String[] { "", "" });children.setPath(routerPath);children.setComponent(UserConstants.INNER_LINK);children.setName(StringUtils.capitalize(routerPath));children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath()));childrenList.add(children);router.setChildren(childrenList);}routers.add(router);}return routers;
}

构建完成,直接返给前台数据,前台请求成功的返回结果:

然后动态添加路由信息,vue2.xxx新api addRouters() 可动态添加路由。

此时,一个完整的从前端 请求验证码 -> 登录 -> 获取用户信息 -> 获取菜单权限 请求流程就结束了。。。
补充下:
前台请求过来的菜单权限,还需要过滤,因为像Component组件名都是字符串,下边是过滤的主要方法,替换前端组件,还有就是把菜单组件变为懒加载状态。

本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
