自己开发完整项目一、登录功能-04(集成jwt)

一、说明

前面文章我们写到了通过数据库查询出用户信息并返回,那么在真实的项目中呢,后端是需要给前端返回一个tocken,当前端通过登录功能认证成功之后,我们后端需要将用户信息和权限整合成一个tocken返回给前端,当前端再次访问别的接口的时候,需要携带着tocken,请求到达后端的时候,后端需要从前端传递过来的tocken中解析出用户信息和权限,判断是否可以访问。


实现思路:在登录中的查询用户中,将权限也查询出来,随后通过jwt来生成tocken和解析tocken

二、 编写jwt工具类(生成tocken和解析tocken)

package com.ljy.myspringbootlogin.utils;import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Component;import javax.crypto.SecretKey;
import java.util.Date;
import java.util.Map;@Component
public class JwtUtils {/*** 创建一个密钥*/private String secret = "Ljy991008X123435asdfSFS34wfsdfsdfSDSD32dfsddDDerQSNCK34SOWEK5354fdgdf4";SecretKey  key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secret));/*** 生成tocken*/public String createTocken(Map<String,Object> map){String tocken = Jwts.builder().setClaims(map).issuedAt(new Date()).expiration(new Date(System.currentTimeMillis() * 30 * 60 * 1000)).signWith(key).compact();return tocken;}/*** 解析tocken*/public Claims parasTocken(String tocken){Jws<Claims> claimsJws = Jwts.parser().verifyWith(key).build().parseSignedClaims(tocken);return claimsJws.getBody();}
}

三、通过jwt工具类将用户信息和权限生成tocken返回给前端

修改userServiceImpl中的代码

package com.ljy.myspringbootlogin.impl;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ljy.myspringbootlogin.commont.Reuslt;
import com.ljy.myspringbootlogin.mapper.UserMapper;
import com.ljy.myspringbootlogin.model.UserModel;
import com.ljy.myspringbootlogin.service.IUserService;
import com.ljy.myspringbootlogin.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;import java.util.*;@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, UserModel> implements IUserService {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate JwtUtils jwtUtils;@Overridepublic Reuslt<UserModel> login(String username, String password) {System.out.println("进入serviceimpl");System.out.println(username);System.out.println(password);//传入用户名和密码UsernamePasswordAuthenticationToken tocken = new UsernamePasswordAuthenticationToken(username, password);System.out.println("tocken"+tocken);//实现登录,此时就会调用loadUserByName//authenticate其实就是userdetailsAuthentication authenticate = null;try{authenticate= authenticationManager.authenticate(tocken);System.out.println("測試!!!!!");}catch (BadCredentialsException e){return Reuslt.error(500,"用户名或者密码错误");}UserModel principal = (UserModel)authenticate.getPrincipal();System.out.println("principal:"+principal);//生成tocken   修改这里就可以HashMap<String,Object> map = new HashMap<>();map.put("id",principal.getId());map.put("username",principal.getUsername());map.put("menuList",principal.getMenuList());map.put("roleList",principal.getRoleList());String tocken1 = jwtUtils.createTocken(map);System.out.println("tocken1"+tocken1);principal.setTocken(tocken1);return Reuslt.ok(principal);}
}

四、编写自定义过滤器(作用:当前端携带tocken访问别的接口的时候,需要进行判断是否有权限访问)

package com.ljy.myspringbootlogin.filter;import com.ljy.myspringbootlogin.model.MenuModel;
import com.ljy.myspringbootlogin.model.RoleModel;
import com.ljy.myspringbootlogin.model.UserModel;
import com.ljy.myspringbootlogin.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;/*** 这个过滤器的作用:* 当某一个用户登录认证成功之后,后端给前端返回一个tocken信息,这个tocken信息里面包含着用户的属性和用户的角色、权限信息* 那么当这个用户再次访问别的接口的时候,后端就需要对前端传递过来的tocken信息进行解析,判断里面是否有权限访问接口** 我们需要集成OncePerRequestFilter,这个是一个抽象类,其中有一个doFilter方法,在doFilter方法中调用了doFilterInternal方法,也是一个抽象方法,所以需要实现* 并且只会在请求之前执行一次** 实现逻辑:* 1.获取前端传递过来的tocken* 2.解析tocken* 3.将解析出来的用户信息和权限使用Authentication告诉给springSecurity框架,springsecurity会将信息存储到SecurityContet中,* 从而放在SecurityContetHolder中* 4.有权限就访问,没有权限就报错*** 注意:登录的时候,只需要放用户名和密码*      登录成功之后请求别的接口的时候,需要放的是用户信息和用户权限**/@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {@AutowiredJwtUtils jwtUtils;/*** 这个方法会被doFilter调用* @param request* @param response* @param filterChain* @throws ServletException* @throws IOException*/@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {/*** 1.获取tocken* 因为前端将tocken信息放到了请求头中,所以我们需要使用request.getHeader("XXXX")来获取tocken*/String tocken = request.getHeader("Authorization");if(tocken == null){doFilter(request,response,filterChain);return;}/*** 2.解析tocken* 使用我们自己编写的工具类,JwtUtils来解析*/Claims claims = jwtUtils.parasTocken(tocken);System.out.println("解析出来的用户信息:"+claims);/*** 3.将解析出来的用户信息和权限使用Authentication告诉给springSecurity框架,springsecurity会将信息存储到SecurityContet中,* 从而放在SecurityContetHolder中*///3.1 从tocken中拿到信息Long id = claims.get("id", Long.class);String username = claims.get("username", String.class);List<String> menuList = claims.get("menuList", ArrayList.class);System.out.println("menuList:"+menuList);List<String> roleList = claims.get("roleList", ArrayList.class);//3.2 将信息放到userModel中UserModel userModel = new UserModel();userModel.setId(id);userModel.setUsername(username);userModel.setMenuList(menuList);//将权限信息转换成Collection<GrantedAuthority> grantedAuthorities = AuthorityUtils.createAuthorityList(menuList.toArray(new String[0]));userModel.setAuthorities(grantedAuthorities);System.out.println("userModel:"+userModel);//3.3 将信息当道SecurityContet中UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =new UsernamePasswordAuthenticationToken(userModel, "", userModel.getAuthorities());SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);System.out.println("userModel.getAuthorities():"+userModel.getAuthorities());//3.4 放行doFilter(request,response,filterChain);}
}

五、将自定义过滤器加载到springsecurity框架的过滤器链中
修改springsecurityConfig

package com.ljy.myspringbootlogin.config;import com.ljy.myspringbootlogin.filter.JwtAuthenticationFilter;
import com.ljy.myspringbootlogin.springSecurityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@EnableWebSecurity //开启springSecurity,会注册大量的过滤器链
@Configuration
@EnableMethodSecurity //开启方法级别的安全校验
public class springSecurityConfig {@Autowiredprivate springSecurityService springSecurityService;@Autowiredprivate JwtAuthenticationFilter jwtAuthenticationFilter;/*** 配置过滤器链* @param http* @return* @throws Exception*/@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{http.csrf().disable();//跨域漏洞防御:关闭http.cors().disable();//跨域拦截关闭http.authorizeHttpRequests().antMatchers("/user/**").permitAll().anyRequest().authenticated();//将自己定义的过滤器添加到过滤器链中//将自定义过滤器放到认证过滤器之前http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);return http.build();}/*** AuthenticationManager:负责认证,也就是认证规则* DaoAuthenticationProvider:负责将springSecurityService和passwordEncoder放进AuthenticationManager中* @return*/@Beanpublic AuthenticationManager authenticationManager(){System.out.println("進入authenticationManager");DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();daoAuthenticationProvider.setUserDetailsService(springSecurityService);//关联使用的密码编码器daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());//将daoAuthenticationProvider放到ProviderManager中ProviderManager providerManager = new ProviderManager(daoAuthenticationProvider);System.out.println("結束authenticationManager");return providerManager;}/*** 密码编码器* @return*/@Beanpublic PasswordEncoder passwordEncoder(){return NoOpPasswordEncoder.getInstance();}
}

六、编写一个测试接口进行验证

package com.ljy.myspringbootlogin.controller;import com.ljy.myspringbootlogin.commont.Reuslt;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {//创建登录控制器@RequestMapping("/test01")@PreAuthorize("hasAnyAuthority('qxgl')")  //需要的权限public Reuslt<String> aaa(){String a="测试";return Reuslt.ok(a);}}

七、postman测试

1.登录生成tocken

2.访问测试接口,并写到上面的tocken

 

八、引入jwt依赖

<!--        引入jwt--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.12.6</version></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.12.6</version><scope>runtime</scope></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId> <version>0.12.6</version><scope>runtime</scope></dependency>

 九、总结

到目前位置,我们实现了前端登录成功之后,通过数据库查询用户信息,并将用户信息生成tocken返回给前端,当前端携带tocken访问权限控制接口的时候,会判断是否有权限,进而判断是否可以访问。
但是存在一个问题,在上面的代码中,我们的接口权限是通过注解的方式写死的,在真实项目中,这个是绝对不可以的,所以我们需要动态实现权限,我们在下一章进行编写!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/52128.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

硬盘数据恢复的正确姿势,这4款神器让你2024年秒变IT达人

现在&#xff0c;数据对我们超级关键&#xff0c;干啥都缺不了。但要是数据没了或者手一滑给删了&#xff0c;那可真够呛。甭管是点错了、电脑故障还是硬件磕了碰了&#xff0c;数据丢了可是大麻烦。不过幸亏科技一直在进步&#xff0c;硬盘数据恢复的技术也越来越厉害&#xf…

最近大模型最火的就业方向有哪些?

在2023和2024年&#xff0c;大语言模型的发展迎来了绝对风口&#xff0c;吸引了大量创业者和投资者。然而&#xff0c;经过一年的发展&#xff0c;许多公司已经销声匿迹。那么&#xff0c;未来大模型方向上还有哪些可以继续发展的方向呢? 基座大模型预训练 现状 - 展现出“胜…

CST软件如何仿真Total Scan方向图的

本期将介绍如何在CST软件中得到Total Scan方向图。 CASE1 首先以两个dipole天线为例&#xff0c;如下图所示&#xff1a; 我们完成这个两单元阵的仿真&#xff0c;可以在远场结果看到各个频点的结果如下图所示&#xff1a; 我们可以在combine按钮下任意合成不同幅度相位下的结…

R-Adapter:零样本模型微调新突破,提升鲁棒性与泛化能力 | ECCV 2024

大规模图像-文本预训练模型实现了零样本分类&#xff0c;并在不同数据分布下提供了一致的准确性。然而&#xff0c;这些模型在下游任务中通常需要微调优化&#xff0c;这会降低对于超出分布范围的数据的泛化能力&#xff0c;并需要大量的计算资源。论文提出新颖的Robust Adapte…

2025入局自动驾驶的秋招人,应该瞄准哪些技术方向?

2024年已过大半&#xff0c;9月随着开学季的来临&#xff0c;2025届的毕业生也纷纷踏出了秋招的第一步。 无论是在学生期间就深耕许久智驾技术、还是从其他赛道转战至智驾&#xff0c;自2023年末一直到今年上半年来&#xff0c;都一直国内智驾行业层出不穷的各种破圈动态刷屏。…

免费OCR 文字识别工具

免费&#xff1a;本项目所有代码开源&#xff0c;完全免费。 方便&#xff1a;解压即用&#xff0c;离线运行&#xff0c;无需网络。 高效&#xff1a;自带高效率的离线OCR引擎&#xff0c;内置多种语言识别库。 灵活&#xff1a;支持命令行、HTTP接口等外部调用方式。 功能…

降Compose十八掌之『羝羊触蕃』| Handle Platform Lifecycles

公众号「稀有猿诉」 原文链接 降Compose十八掌之『羝羊触蕃』| Handle Platform Lifecycles Jetpack Compose是一个独立的声明式UI框架&#xff0c;它并不受限于任何操作系统平台&#xff0c;从框架定位的角度来讲&#xff0c;它是跨平台的&#xff0c;也应该要跨平台。…

OPenCV结构分析与形状描述符(5)查找图像中的连通组件的函数connectedComponents()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 connectedComponents 函数计算布尔图像的连通组件标签图像。 该函数接受一个具有4或8连通性的二值图像&#xff0c;并返回 N&#xff0c;即标签…

机器学习之 PCA降维

1.PCA 降维简介 主成分分析&#xff08;Principal Component Analysis, PCA&#xff09;是一种统计方法&#xff0c;用于在数据集中寻找一组线性组合的特征&#xff0c;这些特征被称为主成分。PCA 的目标是通过变换原始特征空间到新的特征空间&#xff0c;从而减少数据的维度&…

持久化分析

目录 介绍步骤WMI持久化分析注册表映像劫持IFEO持久化 介绍 1、WMI 的全称是 Windows Management Instrumentation&#xff0c;即 Windows 管理规范&#xff0c;在 Windows 操作系统中&#xff0c;随着 WMI 技术的引入并在之后随着时间的推移而过时&#xff0c;它作为一项功能…

Golang | Leetcode Golang题解之第387题字符串中的第一个唯一字符

题目&#xff1a; 题解&#xff1a; type pair struct {ch bytepos int }func firstUniqChar(s string) int {n : len(s)pos : [26]int{}for i : range pos[:] {pos[i] n}q : []pair{}for i : range s {ch : s[i] - aif pos[ch] n {pos[ch] iq append(q, pair{ch, i})} e…

用亚马逊云科技Graviton高性能/低耗能处理器构建AI向量数据库(上篇)

简介&#xff1a; 今天小李哥将介绍亚马逊推出的云平台4代高性能计算处理器Gravition&#xff0c;并利用该处理器构建生成式AI向量数据库。利用向量数据库&#xff0c;我们可以开发和构建多样化的生成式AI应用&#xff0c;如RAG知识库&#xff0c;特定领域知识的聊天机器人等。…

聚铭网络受邀成为ISC终端安全生态联盟首批成员单位

近日&#xff0c;在2024数博会这一行业盛会上&#xff0c;全国首个专注于终端能力的联盟——ISC终端安全生态联盟正式成立&#xff0c;聚铭网络受邀成为该联盟的首批成员单位之一。 ISC终端安全生态联盟由360集团发起&#xff0c;并联合20余家业内领先企业共同创立。联盟旨在通…

Rk3588 Android12 AIDL 开发

AIDL (Android Interface Definition Language) 和 HIDL (HAL Interface Definition Language) 都是 Android 系统中用于定义接口的工具&#xff0c;但它们有不同的用途和特性。 AIDL (Android Interface Definition Language) 用途&#xff1a; 主要用于应用程序之间的进程间…

Windows键盘快捷方式

键盘快捷方式是两个或多个键的组合&#xff0c;可用于执行通常需要鼠标或其他指针设备才能执行的任务。 使用键盘快捷方式你可以更轻松地与电脑进行交互&#xff0c;从而在使用 Windows 和其他应用时节省时间和精力。 大多数应用还提供加速键&#xff0c;以让你能够更轻松地使…

大数据-120 - Flink Window 窗口机制-滑动时间窗口、会话窗口-基于时间驱动基于事件驱动

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

自定义 SpringBoot Starter

文章目录 一、自定义 starter1.1 创建 maven 项目1.2 创建邮件配置属性类1.3 创建模拟邮件发送服务类1.4 创建自动配置类1.5 spring.factories 相关配置1.6 打包成依赖 二、测试项目2.1 创建项目2.2 application.yml 配置2.3 测试应用 参考资料 本文源码位于 java-demos/spring…

Restful风格接口开发

一、项目搭建 安装nestjs脚手架 // 安装nestjs脚手架 npm i nestjs/cli// 新建 nest new [名字]//选择要用的工具 npm / yarn / pnpm 文件信息&#xff1a; 【main.ts】&#xff1a; 入口文件&#xff0c;通过NestFactory&#xff08;由nestjs/core库抛出的对象&#x…

微信小程序手写签名

微信小程序手写签名组件 该组件基于signature_pad封装&#xff0c;signature_pad本身是web端的插件&#xff0c;此处将插件代码修改为小程序端可用。 signature_pad.js /*!* Signature Pad v5.0.3 | https://github.com/szimek/signature_pad* (c) 2024 Szymon Nowak | Releas…

九盾叉车U型区域警示灯,高效照明和安全警示

叉车运作的环境比较复杂&#xff0c;在方便人们物流运输的同时也存在着很大的安全隐患&#xff0c;特别是叉车碰撞人的事故发生率很高&#xff0c;那我们该怎么在减少成本的同时又能避免碰撞事故的发生呢&#xff1f; 九盾叉车U型区域警示灯&#xff0c;仅需一盏灯安装在叉车尾…