news 2026/5/19 12:14:11

别再只写CRUD了!用SpringBoot+Vue给这个Demo加上JWT登录和权限管理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
别再只写CRUD了!用SpringBoot+Vue给这个Demo加上JWT登录和权限管理

从基础Demo到企业级应用:SpringBoot+Vue实现JWT认证与动态权限控制

很多开发者完成前后端分离的基础Demo后,常常陷入"接下来该做什么"的迷茫。本文将带你从简单的任务管理系统出发,逐步引入企业级应用中不可或缺的JWT认证和RBAC权限控制,让你的项目真正具备生产环境可用性。

1. 为什么需要JWT和权限管理

在真实的企业应用中,单纯的数据展示远远不够。想象一下,你的任务管理系统如果任何人都能随意查看、修改所有任务,那将是一场灾难。我们需要解决三个核心问题:

  • 身份认证:确认用户是谁
  • 权限控制:确定用户能做什么
  • 安全传输:确保通信过程不被篡改

JWT(JSON Web Token)作为一种轻量级的认证方案,相比传统的Session有以下优势:

特性JWTSession
存储位置客户端服务端
扩展性适合分布式系统需要共享Session存储
跨域支持天然支持需要额外配置
性能无状态,减少服务端压力需要查询Session存储

2. 后端实现:SpringBoot整合JWT

2.1 引入JWT依赖

首先在pom.xml中添加JJWT依赖:

<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.2</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.2</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.2</version> <scope>runtime</scope> </dependency>

2.2 JWT工具类实现

创建JWT工具类处理token的生成和验证:

public class JwtUtil { private static final String SECRET_KEY = "your-256-bit-secret"; private static final long EXPIRATION_TIME = 864_000_000; // 10天 public static String generateToken(String username, List<String> roles) { return Jwts.builder() .setSubject(username) .claim("roles", roles) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact(); } public static Claims parseToken(String token) { return Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(token) .getBody(); } }

2.3 用户认证服务

实现Spring Security的UserDetailsService:

@Service public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private UserMapper userMapper; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userMapper.findByUsername(username); if (user == null) { throw new UsernameNotFoundException("用户不存在"); } return new org.springframework.security.core.userdetails.User( user.getUsername(), user.getPassword(), getAuthorities(user.getRoles()) ); } private Collection<? extends GrantedAuthority> getAuthorities(List<Role> roles) { return roles.stream() .map(role -> new SimpleGrantedAuthority(role.getName())) .collect(Collectors.toList()); } }

3. 前端实现:Vue整合JWT认证

3.1 登录组件实现

创建登录页面处理用户认证:

<template> <div class="login-container"> <el-form :model="loginForm" :rules="rules" ref="loginForm"> <el-form-item prop="username"> <el-input v-model="loginForm.username" placeholder="用户名"></el-input> </el-form-item> <el-form-item prop="password"> <el-input type="password" v-model="loginForm.password" placeholder="密码"></el-input> </el-form-item> <el-button type="primary" @click="handleLogin">登录</el-button> </el-form> </div> </template> <script> export default { data() { return { loginForm: { username: '', password: '' }, rules: { username: [{ required: true, message: '请输入用户名', trigger: 'blur' }], password: [{ required: true, message: '请输入密码', trigger: 'blur' }] } } }, methods: { handleLogin() { this.$refs.loginForm.validate(valid => { if (valid) { this.$axios.post('/auth/login', this.loginForm) .then(response => { localStorage.setItem('token', response.data.token) this.$router.push('/') }) } }) } } } </script>

3.2 请求拦截器配置

在main.js中添加请求拦截器,自动携带token:

axios.interceptors.request.use(config => { const token = localStorage.getItem('token') if (token) { config.headers.Authorization = `Bearer ${token}` } return config }, error => { return Promise.reject(error) }) axios.interceptors.response.use(response => { return response }, error => { if (error.response.status === 401) { router.push('/login') } return Promise.reject(error) })

4. 动态权限控制实现

4.1 后端权限控制

使用Spring Security配置基于角色的访问控制:

@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/auth/**").permitAll() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/user/**").hasAnyRole("ADMIN", "USER") .anyRequest().authenticated() .and() .addFilter(new JwtAuthenticationFilter(authenticationManager())) .addFilter(new JwtAuthorizationFilter(authenticationManager())) .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); } }

4.2 前端动态菜单

根据用户角色动态生成菜单:

<template> <el-menu :default-active="activeIndex" mode="horizontal"> <template v-for="item in menuItems"> <el-submenu v-if="item.children" :index="item.path" :key="item.path"> <template slot="title">{{ item.title }}</template> <el-menu-item v-for="child in item.children" :key="child.path" :index="child.path" @click="navigateTo(child.path)" > {{ child.title }} </el-menu-item> </el-submenu> <el-menu-item v-else :index="item.path" :key="item.path" @click="navigateTo(item.path)"> {{ item.title }} </el-menu-item> </template> </el-menu> </template> <script> export default { data() { return { activeIndex: '/', menuItems: [] } }, created() { this.fetchMenuItems() }, methods: { fetchMenuItems() { const token = localStorage.getItem('token') if (token) { const payload = JSON.parse(atob(token.split('.')[1])) const roles = payload.roles let items = [] if (roles.includes('ADMIN')) { items = [ { path: '/dashboard', title: '仪表盘' }, { path: '/management', title: '管理', children: [ { path: '/users', title: '用户管理' }, { path: '/tasks', title: '任务管理' } ] } ] } else if (roles.includes('USER')) { items = [ { path: '/dashboard', title: '仪表盘' }, { path: '/tasks', title: '我的任务' } ] } this.menuItems = items } }, navigateTo(path) { this.$router.push(path) } } } </script>

5. 项目优化与安全实践

5.1 Token刷新机制

实现无感知的token刷新:

public class JwtRefreshFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token = resolveToken(request); if (token != null && JwtUtil.canTokenBeRefreshed(token)) { String refreshedToken = JwtUtil.refreshToken(token); response.setHeader("Authorization", "Bearer " + refreshedToken); } filterChain.doFilter(request, response); } private String resolveToken(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { return bearerToken.substring(7); } return null; } }

5.2 敏感操作日志记录

使用Spring AOP记录关键操作:

@Aspect @Component public class OperationLogAspect { @Autowired private OperationLogService logService; @Pointcut("@annotation(com.example.demo.annotation.OperationLog)") public void operationLogPointCut() {} @AfterReturning(pointcut = "operationLogPointCut()", returning = "result") public void afterReturning(JoinPoint joinPoint, Object result) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); OperationLog annotation = method.getAnnotation(OperationLog.class); String username = SecurityContextHolder.getContext().getAuthentication().getName(); String operation = annotation.value(); OperationLogEntity log = new OperationLogEntity(); log.setUsername(username); log.setOperation(operation); log.setMethod(method.getName()); log.setParams(JsonUtil.toJson(joinPoint.getArgs())); log.setResult(JsonUtil.toJson(result)); log.setCreateTime(new Date()); logService.save(log); } }

在实际项目中,我发现JWT的密钥管理尤为重要。曾经因为将密钥硬编码在代码中导致安全漏洞,后来改用环境变量配合配置中心动态获取,大大提升了安全性。另外,前端存储token时建议使用HttpOnly的Cookie,能有效防范XSS攻击。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/19 12:13:46

python系列【仅供参考】:【pymongo】连接认证 auth failed解决方法

【pymongo】连接认证 auth failed解决方法 【pymongo】连接认证 auth failed解决方法 摘要 故事背景: 结果报错: 【pymongo】连接认证 auth failed解决方法 摘要 本文介绍了在使用Python的pymongo库连接MongoDB时遇到的认证失败问题及解决方法。作者在虚拟机上的MongoDB数据…

作者头像 李华
网站建设 2026/5/19 12:07:03

iOS激活锁终极绕过指南:Applera1n免费工具完整使用教程

iOS激活锁终极绕过指南&#xff1a;Applera1n免费工具完整使用教程 【免费下载链接】applera1n icloud bypass for ios 15-16 项目地址: https://gitcode.com/gh_mirrors/ap/applera1n 你是否曾因忘记Apple ID密码而无法使用自己的iPhone&#xff1f;或者购买的二手设备…

作者头像 李华
网站建设 2026/5/19 12:02:11

多双目相机协同的物体三维重建技术研究

摘要 本研究针对多双目相机协同进行物体三维重建的关键技术进行了系统分析,包括多双目相机系统的布局设计与协同工作方式、多视角图像的高效处理流程、点云配准与融合算法以及立体匹配与三角测量的优化方法。研究发现,采用环形或半环形布局的多双目系统能够实现物体的完整视…

作者头像 李华
网站建设 2026/5/19 12:02:10

如何彻底解决电脑风扇噪音?FanControl风扇控制软件终极指南

如何彻底解决电脑风扇噪音&#xff1f;FanControl风扇控制软件终极指南 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Trendi…

作者头像 李华
网站建设 2026/5/19 12:02:06

5MB极致轻量:文泉驿微米黑字体实战深度指南

5MB极致轻量&#xff1a;文泉驿微米黑字体实战深度指南 【免费下载链接】fonts-wqy-microhei Debian package for WenQuanYi Micro Hei (mirror of https://anonscm.debian.org/git/pkg-fonts/fonts-wqy-microhei.git) 项目地址: https://gitcode.com/gh_mirrors/fo/fonts-wq…

作者头像 李华