首先是引入依赖

        <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

默认方案:

首次使用这个空项目的时候他会给你一个默认的账号

账号名为user

密码在控制台输出如下图

这时再进入后端会直接弹到一个/login的地址,输入上述账号密码即可查看路由的具体内容,也可以输出/logout退出登录

springsercurity本质是一个过滤器链

在默认案例中UsernamePasswordAuthenticationFilter中会调用UserDetailService接口的InMemoryUserDetailManager获取用户信息 ,后续我们需要修改成在数据库中查询信息而非内存中

自拟方案:

登录

  1. 自定义登录接口:调用ProviderManager认证,通过则生成jwt,并把用户数据存入redis,自定义UserDetailService,把从内存查数据改成从数据库查
    1. 自定义service继承UserDetailService

      public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
      //查询用户信息
      User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUserName, username));
      if(Objects.isNull(user)){
      throw new RuntimeException("用户名或密码错误");
      }
      String password = user.getPassword();
      //todo 查询权限信息
      //封装返回
      LoginUser loginUser=new LoginUser();
      loginUser.setUser(user);
      return loginUser;
      }
    2. 实现LoginUser类,继承的UserDetails
      public class LoginUser implements UserDetails 
    3. 这里如果进行测试的话,会报错:PasswordEncoder会拿获得的密码和数据库比对,但是要求数据库内的格式为{id}password,根据id去判断加密方式。所以我们写的时候会用BC替换掉这个方法
      @Configuration
      public class SecurityConfig extends WebSecurityConfigurerAdapter {
      @Bean
      public PasswordEncoder passwordEncoder(){
      return new BCryptPasswordEncoder();
      } }

      注:这里使用了bc加密之后数据库的密码也应在添加时替换成加密后的密码.bc提供了matches()和encode()两种方法

    4. 添加拦截配置,给登录方法放行一下
       @Override
      protected void configure(HttpSecurity http) throws Exception {
      http
      .csrf().disable()
      .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeRequests()
      .antMatchers("/user/login").anonymous() //匿名访问:未授权前可以使用,授权之后就不再可以使用
      .anyRequest().authenticated(); // 必须要授权才可以使用
      }
    5. 登录service
      public ResponseResult login(User user) {
      //进行用户认证
      UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
      new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword());
      Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
      if (Objects.isNull(authenticate)) {
      throw new RuntimeException("用户名或密码错误");
      }
      LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
      String id = loginUser.getUser().getId().toString();
      String jwt = JwtUtil.createJWT(id);
      HashMap<String, String> map = new HashMap<>();
      map.put("token", jwt);
      redisCache.setCacheObject("login:"+id,loginUser);
      return new ResponseResult("登录成功", 200, map);
      }
  2. 校验:获取token后解析获取userid,通过redis获取其中用户数据,并将其存入SecurityContextHolder中
    1. 配置过滤器

      @Component
      public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
      @Autowired
      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;
      }
      String userId;
      try {
      Claims claims = JwtUtil.parseJWT(token);
      userId = claims.getSubject();
      } catch (Exception e) {
      throw new RuntimeException(e);
      }
      //从redis中获取用户信息再存入securityContextHolder
      String redisKey = "login:" + userId;
      LoginUser loginUser = redisCache.getCacheObject(redisKey);
      if(Objects.isNull(loginUser)){
      throw new RuntimeException("用户未登录");
      }
      //todo 权限信息还没写
      SecurityContextHolder.getContext().
      setAuthentication(new UsernamePasswordAuthenticationToken(loginUser,null,null));
      filterChain.doFilter(request, response);
      }
      }
    2. 添加过滤器
      @Override
      protected void configure(HttpSecurity http) throws Exception {
      http
      .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
      }

为什么要存入信息到SecurityContextHolder中:后续步骤都需要从其中取数据,如果是未认证的状态会导致后面不放行

为什么上述两个位置同样用到了UsernamePasswordAuthenticationToken方法但作用不同:Authentication表示当前访问系统的用户,封装了用户相关信息。

在第一个构造函数中,1.5登录service:我们使用了AuthenticationManager.authenticate()这一方法对数据进行逻辑验证,验证失败则返回结果为null

而第二个构造函数中,2.1配置过滤器:这里手动设置安全信息,此时已经通过安全检查了

//config的一些参数使用案例
.authorizeRequests()
.antMatchers("/user/login").anonymous()//匿名访问,是指在未授权前可以使用,授权后就不能再使用此功能了
.antMatchers("/example").permitAll()//什么状态都可以访问
.anyRequest().authenticated();//授权后才可以访问

springsecurity使用:登录与校验的更多相关文章

  1. Python3.x:获取登录界面校验码图片

    Python3.x:获取登录界面校验码图片 实例代码: # python3 # author lizm # datetime 2018-06-01 18:00:00 # -*- coding: utf ...

  2. crm 系统项目(一) 登录,注册,校验

    crm 系统项目(一) 登录,注册,校验 首先创建一个Django项目,关于配置信息不多说,前面有~ models.py文件下创建需要的表格信息,之后导入数据库 from django.db impo ...

  3. MVC下用户登录状态校验的问题以及解决方案--------------Action全局过滤器的使用

    前言当我们访问某个网站的时候需要检测用户是否已经登录(通过Session是否为null),我们知道在WebForm中可以定义一个BasePage类让他继承System.Web.UI.Page,重写它的 ...

  4. Spring-Security自定义登录页&inMemoryAuthentication验证

    Spring Security是为基于Spring的应用程序提供声明式安全保护的安全性框架.框架下内容比较多,可以做到按照角色权限对请求路径进行限制.今天主要验证自定义登录页,在内存用户存储中进行请求 ...

  5. SpringSecurity 进行自定义Token校验

    背景 Spring Security默认使用「用户名/密码」的方式进行登陆校验,并通过cookie的方式存留登陆信息.在一些定制化场景,比如希望单独使用token串进行部分页面的访问权限控制时,默认方 ...

  6. SpringSecurity+Token实现权限校验

    1.Spring Security简介 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中配 ...

  7. access登录窗口校验代码一

    Private Sub login_Click()If IsNull(Me.username) ThenMsgBox "请输入用户名!", vbExclamationElseIf ...

  8. SpringBoot+SpringSecurity之如何forword到登录页面

    当我们在项目中引入了SpringSecurity框架进行身份校验的时候,如果某个请求需要用户身份认证,那么SpringSecurity会将用户redirect到登录页面.但是有些时候我们希望是forw ...

  9. SpringSecurity中的Authentication信息与登录流程

    目录 Authentication 登录流程 一.与认证相关的UsernamePasswordAuthenticationFilter 获取用户名和密码 构造UsernamePasswordAuthe ...

  10. js经典校验之注册与登录校验

    平时都专注于后台功能的实现和逻辑需求的分析及数据库方面的设计,很少关注前端的设计,而项目开发过程中专门负责后台是不太可能的事,所以前端我们也需要会用,除了漂亮的首页等其他的交给美工来做,一些功能性的东 ...

随机推荐

  1. 莫烦tensorflow学习记录 (4)Classification 分类学习

    MNIST 数据 首先准备数据(MNIST库) from tensorflow.examples.tutorials.mnist import input_data mnist = input_dat ...

  2. STM32WB55 BLE双核flash擦写程序深度解析

    简介 STM32WB55的flash擦除有两种机制,一种是只有单核运行下的flash擦除,这种模式下,flash擦除的步骤同其他STM32的flash擦除一样,直接调用HAL库中flash擦除的库函数 ...

  3. Aspire项目发布到远程k8s集群

    前提 你必须会创建aspire项目,不会的请先看微服务新体验之Aspire初体验 Aspirate (Aspir8) Aspirate 是将aspire项目发布到k8s集群的工具 安装aspirate ...

  4. 三月二十一日 安卓app个人作业开发

    已经完成了 登录 和 注册逻辑 目前还有 提交打卡记录 的 开始时间 和 结束时间没有弄好 还有个人打卡记录的显示问题 并且我希望增加 修改个人密码 显示个人信息 退出登录 返回页面 删除打卡记录 的 ...

  5. list对象转数组

    list对象转数组 package com.example.core.mydemo.json5; import org.apache.commons.collections4.CollectionUt ...

  6. 有点儿神奇,原来vue3的setup语法糖中组件无需注册因为这个

    前言 众所周知,在vue2的时候使用一个vue组件要么全局注册,要么局部注册.但是在setup语法糖中直接将组件import导入无需注册就可以使用,你知道这是为什么呢?注:本文中使用的vue版本为3. ...

  7. UE 5 NavMesh 烘培 逻辑流程

      关于UE引擎层面的东西: 在向场景重拖入一个NavMeshBoundsVolume时(或者修改时). 会调用 void UNavigationSystemV1::PerformNavigation ...

  8. Built-in COM has been disabled via a feature switch.

    .net 6.0 开始默认关闭com组件 使用时会出现以下信息 Built-in COM has been disabled via a feature switch. See https://aka ...

  9. STP生成树协议详解

    看了网上关于STP生成树的解释感觉不是很懂,随即自己研究了一番 如有错误,欢迎指正,欢迎留言 ----------------------------------------------------- ...

  10. 【ZeroMQ】zguide 第一章 部分翻译

    为了更好的阅读体验,请点击这里 本文大部分内容翻译自 Chapter 1 - Basics,原因是之前翻译的版本太老了,不得不亲自披挂上阵拿机器翻译一下.只截取了部分自己可能用得到的,所以如果有看不太 ...