若依框架后端登录流程深度解析:从验证码到动态路由

若依ruoyi前后端分离版本本地部署全过程 一、下载idea和webstorm 到JetBranins官方下载社区版本的java的编译器 和webstorm 对应图中第二个 二、下载git 进入git官网 下载完成后全部默认安装即可 然后在任意目录下鼠标右键会有Git GUI和Git Bash 说明git安装成功 三、下载若依前后端分离版本 进入若依前后端分离版本的码云界面 复制链接 打开idea,左上角,选择File->New->Project from Vsersion Control… 讲复制的链接拷贝在这里的URL的地 阅读详情

1. 登录流程全景概览:从点击登录到进入首页

大家好,我是老张,在后台系统开发这块摸爬滚打十来年了。今天咱们不聊那些虚头巴脑的概念,直接上手拆解一个非常经典且实用的后台框架——若依(RuoYi)的后端登录流程。很多朋友在用若依做二次开发时,可能只是照着文档配一配,登录功能就跑起来了,但里面到底是怎么一环扣一环工作的,心里可能没那么清楚。搞明白这个,不仅出了问题能快速定位,对你设计自己的权限系统也大有裨益。

简单来说,若依前后端分离版的登录,就是一个典型的“过五关斩六将”的过程。用户在前端登录页面点击“登录”按钮,这个动作会触发后端一连串精密配合的操作,最终目标是为前端生成一个合法的访问凭证(Token),并告诉前端这个用户能看到什么菜单、能操作哪些按钮。整个过程可以粗略分为四个核心阶段:验证码校验、用户身份认证、用户信息与权限拉取、动态路由菜单构建。听起来有点复杂?别急,咱们一步一步,结合代码,把它掰开揉碎了讲。我会尽量用大白话,把每个环节的“为什么”和“怎么做”都讲清楚,让你看完不仅能懂,还能自己动手调试和改造。

2. 第一关:验证码的生成与校验

用户打开登录页,第一眼看到的通常就是那个扭曲的字母数字组合——验证码。这可不是为了为难用户,而是安全防护的第一道简易防线,主要为了防止恶意程序用脚本暴力尝试密码。在若依框架里,这个环节的设计既简洁又典型。

2.1 验证码是如何“画”出来的

当浏览器加载登录页面时,前端会主动调用一个后端接口:/captchaImage。这个接口的活很简单:生成一张验证码图片,以及一个唯一标识(UUID),并把标识和正确的验证码答案临时存起来。

// 示例性的核心逻辑,非完全源码
@GetMapping("/captchaImage")
public AjaxResult getCaptchaImage() {
    // 1. 生成一个随机的唯一标识,比如UUID
    String uuid = IdUtils.fastUUID();
    // 2. 生成4位或5位的随机验证码字符串
    String verifyCode = CaptchaUtils.generateCode(4);
    // 3. 根据验证码字符串,生成一张图片(比如用Kaptcha库)
    BufferedImage image = CaptchaUtils.createImage(verifyCode);
    // 4. 关键一步:把 uuid 和 verifyCode 的对应关系缓存起来,通常设置3-5分钟过期
    redisCache.setCacheObject(CAPTCHA_CODE_KEY + uuid, verifyCode, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
    // 5. 将图片转为Base64编码,和uuid一起返回给前端
    String base64Image = ImageUtils.toBase64(image);
    Map<String, Object> result = new HashMap<>();
    result.put("uuid", uuid);
    result.put("img", "data:image/gif;base64," + base64Image);
    return AjaxResult.success(result);
}

前端拿到这个uuid和img(Base64格式的图片数据),就把图片显示给用户看,同时把uuid悄悄藏起来(通常放在表单的隐藏域或者请求头里),准备在登录时一起提交。这里用Redis做缓存是点睛之笔,保证了验证码数据的快速存取和自动过期,避免了 session 带来的集群部署问题。

2.2 登录时如何验证“码”对不对

用户输入用户名、密码和验证码后点击登录,请求到达后端的 /login 接口。在真正去核对用户名密码之前,系统会先校验验证码,这是登录流程的第一个校验点。

// 在登录服务 LoginService 中
public String login(String username, String password, String code, String uuid) {
    // 0. 校验验证码
    String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
    // 从Redis中取出之前存好的正确验证码
    String captcha = redisCache.getCacheObject(verifyKey);
    // 立即删除已使用的验证码,确保一次性使用
    redisCache.deleteObject(verifyKey);
    
    if (captcha == null) {
        // 记录日志,抛出“验证码过期”的业务异常
        throw new CaptchaExpireException();
    }
    if (!code.equalsIgnoreCase(captcha)) {
        // 记录日志,抛出“验证码错误”的业务异常
        throw new CaptchaException();
    }
    // 验证码通过,才继续后续的用户认证流程...
}

你看,流程非常清晰。先凭uuid去缓存里找答案,找不到就是过期了;找到了就比对用户输入的code,不区分大小写,不一致就报错。校验完不管成功与否,都会把缓存里的验证码删掉,这叫“一次性使用”,防止被人截获了重复使用。这一步如果没过,请求就直接被挡回去了,根本不会去查数据库,有效减轻了数据库的压力,也提升了安全性。

3. 第二关:用户身份认证与Token生成

验证码这关过了,接下来才是重头戏:确认“你是谁”。这个过程主要依托 Spring Security 这个安全框架,若依对它进行了深度定制。我刚开始用 Security 时也觉得绕,但理解其核心就一句话:它提供了一套插件化的认证授权机制,你需要告诉它“怎么获取用户信息”和“怎么判断权限”。

3.1 Spring Security 的认证入口

在 /login 接口的后续处理中,会调用 AuthenticationManager 的 authenticate 方法。这个方法可以理解成 Security 的认证总开关。它需要一个 UsernamePasswordAuthenticationToken 对象,里面装着用户提交的用户名和密码。

// 在登录服务中继续
// 1. 将用户名密码封装成 Security 认识的 Token
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
// 2. 调用 Security 的核心认证管理器进行认证
Authentication authentication = authenticationManager.authenticate(authenticationToken);

这个 authenticate 方法内部会做一系列事情,最终它会调用一个非常关键的接口:UserDetailsService。这个接口只有一个方法 loadUserByUsername(String username)。若依框架通过实现这个接口,告诉 Spring Security:“当需要认证用户时,请按我的方式来查用户信息”。

3.2 自定义用户信息加载:UserDetailsServiceImpl

这是整个认证环节最核心的部分,位于 ruoyi-framework 模块中。我们来看看若依是怎么重写这个方法的。

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private ISysUserService userService;
    @Autowired
    private SysPermissionService permissionService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 1. 根据用户名查询用户实体
        SysUser user = userService.selectUserByUserName(username);
        if (user == null) {
            // 记录日志
            throw new UsernameNotFoundException("用户不存在");
        }
        // 2. 一系列用户状态检查(非常重要!)
        if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
            // 记录日志,抛出“账号已被删除”异常
            throw new UserDeleteException();
        }
        if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
            // 记录日志,抛出“账号已停用”异常
            throw new UserDisableException();
        }
        // 3. 创建并返回自定义的 LoginUser 对象
        return createLoginUser(user);
    }

    public UserDetails createLoginUser(SysUser user) {
        // 重点:查询用户的权限信息(菜单权限和角色)
        Set<String> menuPermission = permissionService.getMenuPermission(user);
        Set<String> rolePermission = permissionService.getRolePermission(user);
        // 将所有权限集合合并
        Set<String> permissions = new HashSet<>();
        permissions.addAll(menuPermission);
        permissions.addAll(rolePermission);
        // 构建 LoginUser 对象,它实现了 UserDetails 接口
        return new LoginUser(user.getUserId(), user.getDeptId(), user, permissions);
    }
}

这段代码有几个关键点。第一,它先根据用户名从数据库里把用户完整信息查出来。第二,它进行了一系列业务状态检查,比如用户是否被删除、是否被禁用。这些检查在实际项目中至关重要,能防止已离职或违规用户继续登录。第三,它没有直接返回查到的 SysUser,而是调用了 createLoginUser 方法,这个方法干了一件大事:查询当前用户的权限集合。

权限查询的逻辑是:先判断这个用户是不是超级管理员(比如 userId == 1)。如果是超管,通常就赋予所有权限,不需要再去数据库查关联表了。如果不是超管,那就得老老实实根据 userId,去查询 sys_user_role、sys_role_menu 这些关联表,找出他拥有的所有角色和菜单权限标识符(比如 system:user:query 这种字符串),最后封装成一个权限集合(Set<String>)。

这个权限集合,最后和用户基本信息一起,被包装进了 LoginUser 对象。LoginUser 实现了 Spring Security 的 UserDetails 接口,所以它可以被 AuthenticationManager 认作是合法的“用户详情”。Security 拿到这个对象后,会自动比对 LoginUser 里封装的密码(从数据库查出的加密后的密码)和用户登录时提交的密码(经过相同加密算法处理后)是否一致。如果一致,认证就通过了。

3.3 登录成功后的收尾工作与Token签发

认证通过后,控制权回到我们自己的登录服务 (LoginService) 中。这时我们已经有了一个认证成功的 Authentication 对象,里面就包含着刚刚那个装满信息的 LoginUser。

// 在登录服务中,认证通过后
// 3. 获取到认证信息中的 LoginUser
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
// 4. 记录登录日志(比如IP、时间、浏览器信息),更新用户最后登录时间
recordLoginInfo(loginUser.getUserId());
// 5. 生成此用户的唯一登录令牌(Token)
String token = tokenService.createToken(loginUser);
// 6. 返回Token给前端
return AjaxResult.success().put(Constants.TOKEN, token);

recordLoginInfo 方法会异步执行,更新用户表里的最后登录IP和时间,同时可能往日志表里插入一条登录记录,这样便于后续审计。重点在 createToken 方法,它负责生成我们常说的 JWT Token。

若依默认使用 JWT(JSON Web Token)作为令牌。生成Token的过程大致是:以 LoginUser 为核心信息,选择一个密钥(secret),设置一个过期时间(比如720分钟),然后用JWT库(如jjwt)生成一个加密的字符串。这个字符串通常分为三部分(Header.Payload.Signature),其中 Payload 部分就包含了用户ID、用户名等关键信息(注意,敏感信息如密码绝不放入)。

// TokenService 中的简化逻辑
public String createToken(LoginUser loginUser) {
    String token = IdUtils.fastUUID(); // 生成一个Token的唯一标识
    loginUser.setToken(token);
    // 将 loginUser 对象以 token 为key,存入Redis,并设置过期时间
    redisCache.setCacheObject(getTokenKey(token), loginUser, expireTime, TimeUnit.MINUTES);
    // 返回给前端的是这个UUID token,而不是JWT字符串本身(具体实现可能不同,有的直接存JWT)
    // 更常见的做法是:用JWT生成字符串,并把 loginUser 信息存入Redis,键为JWT本身或其中的jti
    return token;
}

这里需要说明,若依的Token机制可能有不同版本。一种常见实现是:生成的Token就是一个JWT字符串,JWT的Payload里存有用户ID,然后将这个JWT本身作为Key,把完整的 LoginUser 对象存入Redis。另一种实现(如上面简化代码)是生成一个UUID作为Token键,将 LoginUser 存入Redis,然后将这个UUID返回给前端。前端后续请求时,在请求头(如 Authorization: Bearer <token>)中携带这个Token。后端拦截器会根据Token从Redis中取出 LoginUser,从而恢复用户的登录状态和权限信息。无论哪种,核心思想都是无状态令牌+中心化缓存,兼顾了安全性和灵活性。

4. 第三关:获取用户详情与权限列表

前端拿到Token,登录接口的请求就算成功了。但登录成功只是拿到了“入场券”,用户具体是谁、能干什么,前端还不知道。所以接下来,前端通常会紧接着调用两个接口:/getInfo 和 /getRouters。咱们先看 /getInfo。

4.1 解析Token与获取核心用户信息

前端在登录成功的回调里,或者在全局路由守卫中,会调用 /getInfo 接口。这个接口不需要传额外参数,因为用户的身份信息就藏在请求头携带的Token里。

@GetMapping("/getInfo")
public AjaxResult getInfo() {
    // 1. 从Security上下文中获取当前登录的用户(LoginUser)
    LoginUser loginUser = SecurityUtils.getLoginUser();
    // 2. 根据用户ID查询角色列表
    Set<String> roles = permissionService.getRolePermission(loginUser);
    // 3. 根据用户ID查询权限标识符集合(菜单和按钮)
    Set<String> permissions = permissionService.getMenuPermission(loginUser);
    // 4. 组装数据返回
    Map<String, Object> result = new HashMap<>();
    result.put("user", loginUser.getUser()); // 用户基本信息
    result.put("roles", roles); // 角色编码集合
    result.put("permissions", permissions); // 权限字符串集合
    return AjaxResult.success(result);
}

SecurityUtils.getLoginUser() 是一个工具方法,它背后是从 Spring Security 的 SecurityContextHolder 中获取当前线程绑定的认证信息,再从中提取出我们之前存入的 LoginUser 对象。这个过程是由一个叫 JwtAuthenticationTokenFilter 的过滤器完成的:它在所有接口请求之前,解析请求头中的Token,从Redis里找到对应的 LoginUser,然后把它设置到 Security 的上下文里,这样在整个请求生命周期中,任何地方都能方便地拿到当前用户信息。

注意,这里查询角色和权限,逻辑和登录时 createLoginUser 里类似,但可能更详细。比如角色查询,返回的可能是角色键名集合(如 ["admin", "common"]),而权限查询返回的是类似 ["system:user:add", "system:user:edit"] 这样的按钮级权限标识符。前端拿到这些数据后,通常会存入 Vuex 或 Pinia 这样的状态管理库,用于全局控制页面元素的显示隐藏(比如某个按钮用户没权限就不显示)。

4.2 动态路由菜单的构建原理

用户信息有了,但用户能访问哪些页面(菜单路由)还不知道。这就是 /getRouters 接口的使命。这个接口返回的数据,直接决定了前端侧边栏菜单的渲染。

@GetMapping("/getRouters")
public AjaxResult getRouters() {
    // 1. 获取当前用户ID
    Long userId = SecurityUtils.getUserId();
    // 2. 根据用户ID,查询他有权限访问的菜单列表(已经按父子层级排好序的 SysMenu 列表)
    List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
    // 3. 将后端菜单结构,构建成前端Vue Router能识别的路由结构
    List<RouterVo> routers = menuService.buildMenus(menus);
    return AjaxResult.success(routers);
}

第一步 selectMenuTreeByUserId 是关键。它执行的SQL会比较复杂,需要关联 sys_user_role、sys_role_menu、sys_menu 等多张表,过滤出状态正常、类型为目录或菜单、且对应用户有权限的记录,并且使用递归或CTE(公用表表达式)将结果集处理成树形结构。返回的 List<SysMenu> 里,每个菜单对象可能包含 children 属性,里面就是它的子菜单。

4.3 将数据库菜单转换为前端路由

拿到树形菜单列表后,需要转换成前端路由配置的格式,这是 buildMenus 方法的工作。这个方法理解起来有点绕,因为它需要同时考虑前端路由的多种配置场景。我结合代码和注释,给你梳理一下核心逻辑。

public List<RouterVo> buildMenus(List<SysMenu> menus) {
    List<RouterVo> routers = new LinkedList<>();
    for (SysMenu menu : menus) {
        RouterVo router = new RouterVo();
        // 设置路由基本属性:是否隐藏、路由名称、路径、对应组件
        router.setHidden("1".equals(menu.getVisible())); // 是否隐藏菜单
        router.setName(getRouteName(menu)); // 路由name,用于keep-alive等
        router.setPath(getRouterPath(menu)); // 访问路径
        router.setComponent(getComponent(menu)); // 组件路径,如 "system/user/index"
        // 设置元信息,用于菜单标题、图标、是否缓存等
        router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getIsCache(), menu.getPath()));

        List<SysMenu> cMenus = menu.getChildren();
        // 场景一:当前菜单是目录(TYPE_DIR)且有子菜单
        if (!cMenus.isEmpty() && UserConstants.TYPE_DIR.equals(menu.getMenuType())) {
            router.setAlwaysShow(true); // 始终显示根目录
            router.setRedirect("noRedirect"); // 目录本身不重定向
            // 递归处理子菜单
            router.setChildren(buildMenus(cMenus));
        }
        // 场景二:当前菜单是内嵌框架且无父级(如“首页”)
        else if (isMenuFrame(menu)) {
            router.setMeta(null); // 根路由不显示meta
            // 创建一个子路由,将实际组件放在子级
            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(), menu.getIsCache(), menu.getPath()));
            router.setChildren(Collections.singletonList(children));
        }
        // 场景三:当前菜单是内链(跳转外部链接)
        else if (menu.getParentId().intValue() == 0 && isInnerLink(menu)) {
            router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
            router.setPath("/inner"); // 统一的内链入口路径
            // 创建子路由指向实际外部链接
            RouterVo children = new RouterVo();
            String routerPath = StringUtils.replaceEach(menu.getPath(), new String[]{"http://", "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()));
            router.setChildren(Collections.singletonList(children));
        }
        routers.add(router);
    }
    return routers;
}

这个方法处理了三种前端路由的常见结构。第一种是最普通的目录-菜单树。第二种是“首页”这种特殊页面,它作为顶级菜单,但实际内容是一个组件,这种结构需要包装一层。第三种是内链,点击菜单会跳转到站外链接,这需要映射到一个统一的内链处理组件。最终返回的 List<RouterVo>,其结构完全符合 Vue Router 动态添加路由(router.addRoute())所需的格式。前端拿到这个数据,遍历并动态添加到路由实例中,侧边栏菜单也就随之生成,实现了真正的权限动态路由。

5. 关键细节与实战踩坑点

走完了主流程,咱们再聊聊几个容易出问题或者值得深入理解的细节。这些是我在实际项目开发和团队带人过程中,大家最容易困惑和踩坑的地方。

5.1 权限标识符的设计与使用

若依框架中,权限标识符(Permission)通常对应菜单表(sys_menu)里的 perms 字段。这个字段的字符串怎么设计很有讲究。常见的格式是 模块:功能:操作,比如 system:user:add。在 LoginUser 对象里,这些字符串被存为一个 Set<String>。Spring Security 的权限判断,底层就是看当前用户的这个集合里,是否包含访问某个资源所需的权限字符串。

这个判断发生在哪里呢?通常是通过注解 @PreAuthorize("@ss.hasPermi('system:user:list')") 放在Controller的方法上。这个 @ss 指向一个叫 PermissionService 的Bean,它的 hasPermi 方法会从 Security 上下文取出当前用户的权限集合进行比对。这种设计非常灵活,你可以轻松实现按钮级别的权限控制。但要注意,权限标识符的设计一定要有层次、易管理,避免随意命名导致后期维护混乱。

5.2 Token过期与续期策略

Token是有生命周期的,默认可能是720分钟(12小时)。过期后用户需要重新登录。但在一些体验要求高的系统里,我们希望实现“无感刷新”。若依框架本身可能没有直接提供这个功能,但我们可以基于现有机制实现。一种常见思路是:在Token临近过期时(比如过期前30分钟),前端在请求拦截器中判断,如果某个请求返回了特定的状态码(如401或自定义的Token即将过期码),则自动调用一个刷新Token的接口。

这个刷新接口需要接收旧的Token,验证其有效性(即使快过期,但签名必须正确),然后生成一个新的Token返回给前端,前端替换掉旧的Token。同时,后端需要处理好旧Token的失效问题,避免新旧Token同时有效。更安全的做法是引入Refresh Token机制,但复杂度也会增加。在实现时,务必考虑并发请求下的Token刷新问题,避免短时间内多次刷新。

5.3 菜单与路由的缓存优化

每次登录都去数据库查菜单树并构建路由,如果菜单很多,会对数据库造成压力。一个很实用的优化是引入缓存。我们可以在 menuService.selectMenuTreeByUserId 方法上做文章。例如,以用户ID为Key,将查询到的菜单树结构存入Redis,设置一个较长的过期时间(比如6小时)。这样,同一用户在过期时间内的多次登录或刷新页面,都能直接从缓存获取菜单,性能提升非常明显。

但要注意缓存更新问题。当管理员在后台增删改菜单或调整权限后,需要清除或更新相关用户的菜单缓存。一个简单的办法是,在修改菜单或角色权限关联关系的Service方法中,清除所有相关的用户菜单缓存(可以使用通配符Key),或者更精细地只清除受影响的用户缓存。这需要根据业务量来权衡实现的复杂度。

5.4 前后端协作的注意事项

动态路由功能强大,但对前后端协作要求也高。首先,后端菜单表里的几个字段必须和前端的路由配置约定好,比如 component 字段对应的是前端 views 目录下的文件路径,这个路径必须真实存在,否则前端动态加载组件时会报错。其次,关于“是否缓存”(isCache)这个字段,需要前后端对 keep-alive 的理解一致,否则可能会遇到页面状态不保存或者保存错乱的问题。

在开发联调时,我建议先在后端把 /getRouters 接口的返回数据打印出来,对照着前端的路由配置规则,一条一条地检查 path、name、component、meta 等字段是否正确映射。特别是嵌套路由和重定向的配置,很容易出错。另外,前端在动态添加路由后,如果遇到页面刷新白屏,通常是新添加的路由没有正确应用到路由实例上,或者路由守卫的逻辑有问题,需要仔细检查Vue Router的 addRoute 调用时机和路由守卫的跳转逻辑。

前后端分离项目部署(若依) 这通常在开发和测试环境中比较常见,因为在这些环境下,对数据传输的安全性要求可能较低,而且SSL加密会增加一些额外的性能开销。在这种情况下,如果数据库服务器不要求强制的SSL连接,你可以将useSSL参数设置为false来简化连接配置。SSL是一种用于在计算机网络上提供安全通信的协议,它可以确保在客户端和服务器之间传输的数据在传输过程中是加密的,从而提供了一定程度的安全性。但是,在生产环境中,特别是涉及到敏感数据的应用,强烈建议使用SSL加密来保护数据的传输安全性。关闭selinux、防火墙。 阅读详情

相关推荐

若依框架SpringBoot登录流程全解析:从验证码到动态路由的完整实现

本文深入解析了若依框架SpringBoot后端的登录流程,从验证码校验、Spring Security认证到动态路由生成的完整实现。详细拆解了用户认证、权限数据加载与前端资源同步的核心机制,并探讨了性能优化与安全实践,为开发者构建健壮的企业级权限系统提供实战指导。

weixin_29228781的博客 214

全面解析若依框架(springboot-vue前后分离--后端部分)

自定义隐藏列通过excludeFields数组来进行控制,在List getFields获取字段信息的时候将通过excludeFields来进行字段排除,使用hideColumn(“userId”)方法来隐藏,使用方法如下。

qq_46624276的博客 2万+

若依框架深度解析:从企业级脚手架到二次开发实战指南

在Java企业级应用开发领域,Spring Boot作为核心框架,极大地简化了项目初始化和配置流程。其核心原理在于通过约定大于配置的理念,提供了一套标准化的项目结构和自动配置机制,从而显著提升开发效率。这一技术价值在于让开发者能够快速构建稳定、可扩展的后台管理系统,尤其适用于需要快速交付的中小型项目或内部运营平台。在实际应用场景中,开发者常基于此类框架进行二次开发,集成用户权限、菜单管理等通用模块,以快速搭建业务系统。本文聚焦于若依框架,这是一个基于Spring Boot的流行脚手架,深入探讨其核心架构、代

weixin_30435261的博客 476

若依框架:登陆(后端)

若依框架:登陆(后端)

大连赵哥的博客 1456

影刀RPA验证码识别指令全解析:从官方AI到Python ddddocr,哪种方案更适合你?

本文深度评测了影刀RPA中的验证码识别方案,对比官方AI引擎与开源工具ddddocr的技术特点与应用场景。通过详细的技术解析和实战指南,帮助用户根据成本、技术能力、安全合规等维度选择最适合的验证码识别方案,提升RPA自动化流程的效率和稳定性。

weixin_29085865的博客 218

深入解析若依框架:Vue-Router导航守卫如何控制初始页面跳转

本文深入解析了若依框架中Vue-Router导航守卫如何控制项目初始页面跳转。核心在于全局前置守卫`router.beforeEach`,它通过检查Token和校验白名单,将未登录用户从根路径重定向至登录页,从而构建了前端权限控制的基础。文章详细剖析了permission.js文件的实现逻辑与设计意图。

weixin_28077113的博客 354

使用若依框架RuoYi前后端分离版(超详细步骤)

RuoYi-Vue是一款基于SpringBoot+Vue的前后端分离极速后台开发框架。

thewhat的博客 6万+

若依 v3.8.7 权限控制实战:从登录到动态菜单的完整流程解析

本文详细解析了若依 v3.8.7 框架基于SpringBoot的权限控制实战,从用户登录到动态菜单生成的完整流程。通过JWT认证、Spring Security授权及RBAC模型,实现灵活可靠的权限体系,助力开发者构建高效安全的企业级后台管理系统。

weixin_26763955的博客 371

若依框架登录流程中的权限控制与动态路由实现(附完整代码示例)

本文深度解析了若依框架在企业级应用中的登录流程与权限控制机制。通过剖析UserDetailsService定制、JWT令牌传递及SecurityContext构建,详细阐述了用户认证与权限信息流转的全过程。同时,结合完整代码示例,展示了如何根据用户权限动态生成前端路由树,并实现Vue端的动态注入与全局守卫,为构建安全、灵活的后台管理系统提供了实战指南。

app77的博客 91

微信扫码登录全流程实战:Spring Security + OAuth2 + JWT 深度解析

用户认证与授权是现代Web应用安全架构的核心基石。其原理在于,系统需要先确认用户身份(认证),再决定其可访问的资源(授权)。为实现安全、可扩展的认证,无状态令牌技术应运而生,它允许服务端将验证信息封装于令牌中,由客户端保管,从而摆脱了传统会话对服务器状态的依赖,完美契合分布式架构。JWT(JSON Web Token)正是这一技术的典范,它通过自包含的签名令牌,在保障安全的同时提升了性能。而在涉及第三方身份(如微信)登录的场景中,OAuth 2.0协议成为实现安全委托授权的行业标准,其授权码模式能有效保护敏

weixin_33984032的博客 432

若依前后端分离部署Nginx代理配置详解:解决401认证失败与验证码加载问题

在前后端分离架构中,Nginx反向代理是实现前端静态资源服务与后端API请求转发的关键技术组件。其核心原理是通过配置location规则匹配请求路径,并使用proxy_pass指令将特定前缀的请求转发至后端应用服务器,同时通过路径重写确保请求路径与后端路由匹配。这一机制对于保障系统通信链路的完整性至关重要,尤其在处理用户认证、会话管理等安全敏感场景时,配置不当极易引发401未授权错误。本文以若依框架部署中常见的验证码接口401错误为切入点,深入剖析了前端baseURL配置、Nginx路径重写规则与Sprin

weixin_33785108的博客 460

若依框架登录模块深度改造:五大实用技巧提升安全性与多端适配

在构建企业级后台管理系统时,登录认证是保障系统安全的第一道防线。其核心原理通常基于Spring Security等安全框架,通过用户名、密码及验证码等多因素验证用户身份,并生成令牌(Token)维持会话。这一基础架构的技术价值在于为应用提供了标准的认证与授权能力,但面对真实生产环境中的安全审计、高并发及多端访问等复杂场景时,往往需要进行深度定制。例如,通过集成行为验证码(如滑动拼图)替代简单的算术验证码,能有效抵御自动化攻击;而设计支持Web、APP、小程序等多端识别的统一Token管理体系,则是实现统一认

areen7003的博客 470

RDD2022 数据格式转换与清洗

Rdd2022数据集,是关于道路损伤的数据集,与rdd2020相比增加了两万多张图片但是由于格式不能被yolo直接使用且其中有大量的图片没有符合要求的标注,特写此文章记录数据清洗与格式化的过程。

蓝胖子的博客 9962

若依前后端分离版实战:从零搭建到核心功能深度解析

本文提供了一份详细的若依前后端分离版实战指南,涵盖从环境准备、项目启动到核心功能的深度源码解析。文章手把手指导如何搭建项目,并深入剖析了验证码登录流程、动态菜单与RBAC权限管理、用户管理及高效代码生成器的使用,最后通过二次开发实例演示了功能扩展方法,帮助开发者快速掌握并定制这一流行的Java后台管理系统。

uber9的博客 191

Python数据分析实战:用TIGRAMITE库5步搞定时间序列因果分析(附完整代码)

本文详细介绍了如何使用TIGRAMITE库进行时间序列因果分析,通过5个步骤从环境配置到模型优化,帮助读者掌握因果关系库的应用。附完整代码示例,适合数据分析师和研究人员快速实现复杂时间序列的因果发现。

weixin_29050271的博客 161

RFSOC实战解析(一):深入RF Data Converter的时钟与数据接口设计

本文深入解析RFSOC中RF Data Converter的时钟与数据接口设计,涵盖GHz采样、数据流处理、时钟树同步及AXI-Stream接口实战。通过详细案例和调试技巧,帮助工程师高效配置IP核,优化ADC/DAC性能,解决跨时钟域和信号完整性等关键问题。

weixin_30955617的博客 474

[RuoYi二次开发]从源码到实践:深度剖析登录与退出的安全机制与扩展

本文深入解析了RuoYi框架的登录与退出安全机制,包括验证码生成、Token管理、权限初始化等关键环节,并提供了二次开发中的安全增强实践与性能优化建议。特别适合需要进行RuoYi二次开发的开发者,帮助构建更安全的认证系统。

weixin_42692935的博客 412

ThingsKit物联网平台产品管理之物模型

物模型是ThingsKit物联网平台为产品定义的数据模型,用于描述产品的功能。本文介绍物模型相关概念和使用限制。

云腾五洲官方博客 1174

吃透 RuoYi-Vue 权限体系:彻底搞懂登录鉴权、功能权限、数据权限,一篇就够

本文聚焦 RuoYi-Vue 框架的权限体系展开深度解析,通过系统化的梳理与实战演示,你将收获: 1. 清晰掌握 RuoYi-Vue 基于 Spring Security + JWT 的登录认证授权全流程,理解身份校验、Token 生成与校验的核心逻辑; 2. 精准理解功能权限(菜单、按钮、接口)与数据权限的核心概念,区分两类权限在系统中的定位与价值; 3. 深入剖析 RuoYi-Vue 功能权限(菜单权限、按钮权限、接口权限)和数据权限的底层实现原理,包括动态路由、自定义指令、AOP 切面、动态 SQL

热爱编程、热爱生活、热爱探索 1670

极智嘉嵌入式面试题及参考答案

IIC(Inter-Integrated Circuit)即集成电路总线,是一种由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器及其外围设备。它仅使用两根线,即串行数据线 SDA 和串行时钟线 SCL,就能实现多个设备之间的通信,具有简单、高效、占用资源少等优点,广泛应用于各种嵌入式系统中。

大模型大数据攻城狮的专栏 922

信息安全管理与评估赛题解析-单机取证(含环境)

链接:https://pan.baidu.com/s/1OMzIq884dW2vAiUp0k2Ppg。链接:https://pan.baidu.com/s/1i5daMqhD53wYeQ6hYzRK6Q。链接:https://pan.baidu.com/s/1QFAjdQZK4sJ-gGRP42XPKA。链接:https://pan.baidu.com/s/1BSXvqN2ZGCQXewgFULoeyQ。链接:https://pan.baidu.com/s/1g9zu5ngBz_KMjW1eBMkJAw。

Brucye 1835

基于若依 RuoYi-Vue v3.8.2 的 CSMD 架构实践与登录流程深度解析

Getter 和 Setter 方法通过本次从单表 CRUD 代码的编写,到深入剖析 RuoYi-Vue 的登录源码,我们小组对现代前后端分离架构有了更具象的理解。在实操层面,我们踩过了 Spring Security 路径拦截(401错误)和 MyBatis 结果集映射失败(全 null 数据)的坑,这些排错过程极大锻炼了我们的工程化思维。

celentwo的博客 833

ubuntu-25.04-desktop-amd64 工具VMware-tools 正确安装方法

摘要:Ubuntu 25.04虚拟机安装VMware Tools后无法实现主机与虚拟机间的文件复制粘贴和拖拽功能,问题可能源于工具兼容性。建议优先安装open-vm-tools套件(含open-vm-tools-desktop),而非官方VMware Tools。具体方案:通过终端执行安装命令后重启系统。该方法已实测有效解决该兼容性问题。(149字)

安徽锐锋科技-沐雨潇竹 672
上一篇: Cat.1模块(EC600N)在野外物联网设备中的低功耗实践指南
下一篇: MOS管音频放大电路实战:从原理到调试的全过程记录(含示波器测试数据)
java5
博客等级 码龄22年 85粉丝 2103原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值