若依框架后端登录流程

您所在的位置:网站首页 判断用户是否登录怎么实现 若依框架后端登录流程

若依框架后端登录流程

2023-07-02 15:24| 来源: 网络整理| 查看: 265

若依框架前后端分离 项目(前端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 menus 结果为:

 最后,构建前端需要的路由树,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/false router.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组件名都是字符串,下边是过滤的主要方法,替换前端组件,还有就是把菜单组件变为懒加载状态。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3