springSecurity(二):实现登入获取token与解析token

登入生成token

主要思想

  1. springSecurity使用UsernamePasswordAuthenticationToken类来封装用户名和密码的认证信息

代码实现

发起登入请求后,进入到login()方法

  /**
   * 在接口中我们通过AuthenticationManager的authenticate方法来进行用户认证,
   * 所以需要在SecurityConfig中配置把AuthenticationManager注入容器。
   * @param user
   * @return
   */
  @Override
  public ResponseResult login(User user) {
    //通过AuthenticationManager的authenticate方法来进行用户认证
    UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword());
    Authentication authenticate = authenticationManager.authenticate(token);

    //如果没通过,给出对应的提示
    if(Objects.isNull(authenticate)){
      throw new RuntimeException("用户名或密码错误");
    }

    //如果通过了,使用userId生成一个jwt,存入ResponseResult返回
    LoginUser loginUser = (LoginUser)authenticate.getPrincipal();
    String id = loginUser.getUser().getId().toString();
    
    //根据用户id生成token
    String jwt = JwtUtil.createJWT(id);

    //把完整的用户信息存入redis,使用userId作为key
    redisCache.setCacheObject("login:"+id,loginUser);

    ResponseResult responseResult = new ResponseResult();
    responseResult.setCode(200);
    responseResult.setMsg("登入成功");
    Map<String,String> map = new HashMap<>();
    map.put("token",jwt);
    responseResult.setData(map);

    return responseResult;
  }


在执行 Authentication authenticate = authenticationManager.authenticate(token);时,会调用security框架的loadUserByUsername方法查询用户信息,这里我们重写loadUserByUsername方法

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

  @Autowired
  private UserMapper userMapper;

  @Autowired
  private MenuMapper menuMapper;

  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

    //查询用户信息
    LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    lambdaQueryWrapper.eq(User::getUserName,username);
    User user = userMapper.selectOne(lambdaQueryWrapper);

    //如果没有查询到用户就抛出异常
    if (Objects.isNull(user)){
      throw new RuntimeException("用户名或密码错误");
    }

    //查询对应的权限信息
    List<String> list = menuMapper.selectPermsByUserId(user.getId());

    //把数据封装成UserDetails返回
    return new LoginUser(user,list);
  }
}

这样执行完loadUserByUsername方法之后,就把权限信息封装到LoginUser中

效果展示

调用接口之后返回一个token信息

{
    "code": 200,
    "msg": "登入成功",
    "data": {
        "token": "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJiODhkZmIxZjExMDg0NmZhOTJlN2I5OTM4M2Q3ZTQ5NyIsInN1YiI6IjQiLCJpc3MiOiJ3aHMiLCJpYXQiOjE3MTg2MjQyMTAsImV4cCI6MTcxODYyNzgxMH0.Z-qa-1rD6dIOxKSaeZ_wjHFKs_TY31hFgZnl2Yld4M4"
    }
}

题外话

看以下UsernamePasswordAuthenticationToken源码的实现思想

public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
    
}

public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer {
    
}

这段代码同时可以参考ArrayList的实现思想

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{ 
}


public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
}

思想理论基础

  • 抽象类是一种特殊的类,它的方法体包含抽象方法和非抽象方法
    • 抽象方法是一种没有具体实现的方法,必须在子类被重写实现
    • 非抽象方法是有具体实现的方法,可以在子类中被继承使用
    • 抽象类的主要目的是为了被继承和重写,而不是被实例化
  • 当一个类继承了一个抽象类和实现了一个接口之后,如果抽象类和接口都有方法A(),这个类是否需要实现方法A()呢?
    • 答案是不需要。因为当抽象类和接口中含有相同的方法名、参数列表和返回类型时候,这个类并不需要强制重写这个方法。
    • 接口默认方法和抽象类中的抽象方法是不同的概念,它们可以共存而不会产生冲突

优点

  1. extends抽象类提供了基础实现
    抽象类可以包含部分已实现的方法和成员变量,使子类能够继承这些实现,减少重复代码。例如:
abstract class Animal {
    String name;
    void sleep() {
        System.out.println(name + " is sleeping.");
    }
    abstract void makeSound();
}

  1. implements接口提供了灵活性
    接口定义了一组方法,子类必须实现这些方法。这强制子类提供具体实现,同时接口可以用于实现多重继承,因为一个类可以实现多个接口。例如:
interface Pet {
    void play();
}
  1. 组合使用的话:
    抽象类提供基础功能,接口提供额外功能
public class Dog extends Animal implements Pet {
    public Dog(String name) {
        this.name = name;
    }
    @Override
    void makeSound() {
        System.out.println(name + " says: Woof!");
    }
    @Override
    public void play() {
        System.out.println(name + " is playing.");
    }
}

  1. 灵活的接口实现
    通过实现接口,一个类可以被视为实现该接口的对象类型,这使得代码更加灵活和松耦合
public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog("Buddy");
        dog.sleep(); // Animal类的方法
        dog.makeSound(); // Dog类实现的抽象方法
        dog.play(); // Pet接口的方法

        Pet pet = dog; // 可以用接口类型引用对象
        pet.play(); // 接口的方法
    }
}
  1. 设计模式的支持
    这种组合模式在策略模式和模板方法模式得到了广泛应用。抽象类可以提供通用的算法结构,接口可以定义可替换的行为。

总结

  • 代码复用:继承抽象类可以重用父类的代码。
  • 灵活性:实现接口可以实现多重继承,提供额外功能。
  • 松耦合:接口使得代码更加灵活和易于扩展。
  • 支持设计模式:这种组合在很多设计模式中被广泛应用,提高代码的可维护性和可扩展性。

请求解析token

前端登入获取token之后,之后其他请求在访问接口时候都需要带上token

主要思想

  • 在SpringSecurity中,会使用默认的FilterSecurityInterceptor来进行权限校验。在FilterSecurityInterceptor中会从SecurityContextHolder获取其中的Authentication,然后获取其中的权限信息。当前用户是否拥有访问当前资源所需的权限。
  • 所以我们在项目中只需要把当前登录用户的权限信息也存入Authentication。然后设置我们的资源所需要的权限即可。

代码实现

开启配置

在SecurityConfig类上加上如下注解

@EnableGlobalMethodSecurity(prePostEnabled = true)

在接口上加@PreAuthorize注解

  /**
   * 测试
   * @return
   */
  @RequestMapping("/hello")
  @PreAuthorize("ex.hasAuthority('sysytem:dept:list')")
  public String hello(){
    return "hello";
  }

重写认证过滤器,解析token

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

  @Autowired
  private RedisCache redisCache;

  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    //获取token
    String token = request.getHeader("token");
    if(!StringUtils.hasText(token)){
      //放行
      filterChain.doFilter(request,response);
      return;
    }

    //解析token
    String userId;
    try {
      Claims claims = JwtUtil.parseJWT(token);
      userId= claims.getSubject();
    } catch (Exception e) {
      throw new RuntimeException("token非法");
    }

    //从redis中获取用户信息
    String redisKey = "login:"+userId;
    LoginUser loginUser = redisCache.getCacheObject(redisKey);
    if(Objects.isNull(loginUser)){
      throw new RuntimeException("用户未登入");
    }

    //存入SecurityContextHolder
    //获取权限信息,封装到Authentication中
    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser,null,loginUser.getAuthorities());
    SecurityContextHolder.getContext().setAuthentication(authenticationToken);

    //放行
    filterChain.doFilter(request,response);

  }
}

效果展示

在header加上token之后可以请求到正确结果
image.png
如果不加token,则会报错401
image.png

后台回复springSecurity获取项目完整代码

搜索框传播样式-白色版

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL----表级锁行级锁排它锁和共享锁意向锁

MySQL的锁机制 锁&#xff08;Locking&#xff09;是数据库在并发访问时保证数据一致性和完整性的主要机制。在 MySQL 中&#xff0c;不同存储引擎使用不同的加锁方式&#xff1b;我们以 InnoDB 存储引擎为例介绍 MySQL 中的锁机制&#xff0c;其他存储引擎中的锁相对简单一些…

隐藏element的DateTimePicker组件自带的清空按钮

管理台页面使用到el-date-picker&#xff0c;type datetimerange 但是组件自带了清空按钮&#xff0c;实际上这个控件业务上代表开始时间和结束时间是一个必填选项&#xff0c;所有想要把清空按钮隐藏掉。 查看了文档https://element.eleme.io/#/zh-CN/component/datetime-p…

C++内联函数-auto关键字-for循环-空指针

内联函数 1.1概念&#xff1a; 以 inline 修饰 的函数叫做内联函数&#xff0c; 编译时 C 编译器会在 调用内联函数的地方展开 &#xff0c;没有函数调 用建立栈帧的开销&#xff0c;内联函数提升程序运行的效率。 #define _CRT_SECURE_NO_WARNINGSint ADD(int left, int rig…

【Pandas驯化-07】DataFrame中无所不能的pivot函数

【Pandas驯化-07】DataFrame中无所不能的pivot函数 本次修炼方法请往下查看 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合&#xff0c;智慧小天地&#xff01; &#x1f387; 相关内容文档获取 微信公众号 &#x…

前端菜鸡学习日记 -- 关于pnpm

哈咯哇大家&#xff0c;我又来了&#xff0c;最近稍微悠闲一些&#xff0c;所以就趁着这个机会学习一些新的知识&#xff0c;今天就是碰巧遇到了pnm&#xff0c;这个可以看作是npm的升级版本&#xff0c;比npm要快&#xff0c;用起来也更得劲更迅速 官网地址&#xff1a;https…

OpenGL系列(六)变换

在三角形和纹理贴图示例中&#xff0c;顶点使用的是归一化设备坐标&#xff0c;在该坐标系下&#xff0c;顶点的每个轴的取值为-1到1&#xff0c;超出范围的顶点不可见。 基于归一化设备坐标的物体的形状随着设备的大小变换而变化&#xff0c;这里产生的第一个问题是&#xff0…

数学学习与研究杂志社《数学学习与研究》编辑部2024年第6期目录

课改前沿 基于核心素养的高中数学课堂教学研究——以“直线与圆、圆与圆的位置关系”为例 张亚红; 2-4 核心素养视角下初中生数学阅读能力的培养策略探究 贾象虎; 5-7 初中数学大单元教学实践策略探索 耿忠义; 8-10《数学学习与研究》投稿&#xff1a;cn7kantougao…

微信ipad协议8049新版本

首先我们要先了解下ipad协议是什么 &#xff0c;ipad协议又叫微信协议 是基于微信IPad协议的智能控制系统帮助企业快速连接客户&#xff0c;创造营销氛围&#xff0c;实现自动获客、自动传播、自动转化、智能营销等分布式营销服务。 通过API 实现 个性化微信功能 &#xff08;例…

精度丢失引起的支付失败问题

问题描述 在提交订单时候&#xff0c;输入充值金额和优惠码&#xff0c;后台会返回具体的订单信息&#xff0c;如下图&#xff0c;支付金额应该是1 * (1 - 0.09) 0.91&#xff08;这个是理想状态&#xff09;&#xff0c;但是表单显示的是0.90999997&#xff0c; 然后点击确…

React+TS前台项目实战(十二)-- 全局常用组件Toast封装,以及rxjs和useReducer的使用

文章目录 前言Toast组件1. 功能分析2. 代码详细注释&#xff08;1&#xff09;建立一个reducer.ts文件&#xff0c;用于管理状态数据&#xff08;2&#xff09;自定义一个清除定时器的hook&#xff08;3&#xff09;使用rxjs封装全局变量管理hook&#xff08;4&#xff09;在to…

2025计算机毕业设计选题题目推荐-毕设题目汇总大全

选题在于精&#xff0c;以下是推荐的容易答辩的选题&#xff1a; SpringBoot Vue选题: 基于SpringBoot Vue家政服务系统 基于SpringBoot Vue非物质文化遗产数字化传承 基于SpringBoot Vue兽医站管理系统 基于SpringBoot Vue毕业设计选题管理系统 基于SpringBoot Vue灾害应急救援…

使用Ollama+OpenWebUI本地部署阿里通义千问Qwen2 AI大模型

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;AI大模型部署与应用专栏&#xff1a;点击&#xff01; &#x1f916;Ollama部署LLM专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年6月17日22点50分 &#x1f004;️文章质量&#xff…

safari浏览器无法连接到服务器

问题&#xff1a;MacBook pro&#xff0c;网络连接正常&#xff0c;可以使用各种软件上网&#xff0c;唯独safari浏览器打不开网页&#xff0c;报错说Safari无法连接到服务器&#xff1b; 原因&#xff1a;使用了VPN&#xff0c;VPN自动更改了网络设置&#xff0c;导致Safari浏…

数据结构-十大排序算法集合(四万字精讲集合)

前言 1&#xff0c;数据结构排序篇章是一个大的工程&#xff0c;这里是一个总结篇章&#xff0c;配备动图和过程详解&#xff0c;从难到易逐步解析。 2&#xff0c;这里我们详细分析几个具备教学意义和实际使用意义的排序&#xff1a; 冒泡排序&#xff0c;选择排序&#xff0c…

【vue大作业-端午节主题网站】【预览展示视频和详细文档】

vue大作业-端午节主题网站介绍 端午节&#xff0c;又称为龙舟节&#xff0c;是中国的传统节日之一&#xff0c;每年农历五月初五庆祝。这个节日不仅是纪念古代爱国诗人屈原的日子&#xff0c;也是家人团聚、共享美食的时刻。今天&#xff0c;我们非常高兴地分享一个以端午节为…

建筑学跑路:揭秘热门转行新选择!

话说建筑学真的是我见过最关心同行的专业&#xff0c;每个建筑学跑路的帖子下面都有人问&#xff1a;你跑哪里去了&#xff1f; 很多人表示&#xff0c;我也想跑 当然不仅建筑学&#xff0c;园林的、城规的、土木的也会来凑热闹&#xff1a; 很多小伙伴分享了自己的转行经历&a…

用这个神级提示词插件,能让你的AI绘画工具Stable diffusion提示词直接写中文!

大家好&#xff0c;我是设计师阿威 最近&#xff0c;有同学在使用AI绘画工具 Stable Diffusion的时候和我说&#xff1a;老师&#xff0c;我英文不好&#xff0c;能不能直接让我写中文提示词啊&#xff1f;最好可以直接在SD的输入框就能直接写中文&#xff0c;不用切换网页或者…

哪个充电宝牌子好用又实惠?盘点四大平价充电宝分享

在当今快节奏的生活中&#xff0c;充电宝已成为我们日常生活中不可或缺的一部分。然而&#xff0c;面对市场上琳琅满目的充电宝品牌和型号&#xff0c;许多消费者误以为选择容量越大、价格越高的充电宝就是最好的选择。实际上&#xff0c;买充电宝并不是一味追求高容量和高价格…

好用的加密软件谁在用啊?不会吧,还不知道迅软DSE加密软件好用?

说起加密软件想必大家都不陌生&#xff0c;就是用来保护机密数据的&#xff0c;防止泄密行为的出现&#xff0c;那么重点来了&#xff0c;想要完全的把机密信息保护起来&#xff0c;那就用到了加密软件&#xff0c;需要选择一款靠谱、有效果的加密软件才能实现加密&#xff0c;…

2024信息系统、信号处理与通信技术国际会议(ICISPCT2024)

2024信息系统、信号处理与通信技术国际会议&#xff08;ICISPCT2024) 会议简介 2024国际信息系统、信号处理与通信技术大会&#xff08;ICISPCT2024&#xff09;将在青岛隆重开幕。本次会议旨在汇聚全球信息系统、信号处理和通信技术领域的专家学者&#xff0c;共同探索行业…