首先是引入依赖

        <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. TS码流解析(二)PSI PAT PMT

    TS码流有PSI和PES两种负载,这一节主要来了解PSI是如何解析的. 1.PSI PSI(Program Specific Information)节目专用信息,用来描述TS码流的节目组成等信息.P ...

  2. 在 Flask 项目中配置 Session:简明指南

    在 Flask 项目中配置 Session:简明指南 本文介绍如何在 Flask 项目中配置会话 1. Flask 内置会话 Flask 自带会话管理功能,使用客户端 Cookie 存储会话数据.默认 ...

  3. itest(爱测试) 4.5.5 发布,开源BUG 跟踪管理 & 敏捷测试管理&极简项目管理软件

    itest 简介 itest 开源敏捷测试管理,testOps 践行者,极简的任务管理,测试管理,缺陷管理,测试环境管理4合1,又有丰富的统计分析.可按测试包分配测试用例执行,也可建测试迭代(含任务, ...

  4. k8s核心组件详解和分层架构

    k8s核心组件 master中的核心组件 api-server(接口服务,基于rest风格开放k8s接口的服务) kube-controller-manager(管理各个类型的控制器,针对k8s中的各 ...

  5. 01-布局扩展-BFC完成圣杯布局

    <!DOCTYPE html>   <html lang="en">   <head>   <meta charset="UTF ...

  6. Win11系统下的MindSpore环境搭建

    技术背景 笔者尝试过不少编程环境搭建的方案,例如常见的Ubuntu.Deepin.CentOS,也用过很多人力荐的Manjaro,这些发行版在需要办公的条件下,一般都需要结合Windows双系统使用. ...

  7. CF1777E

    problem & blog 反转的边最大权值最小,想到二分. 于是二分代价即可. 反转代价小于二分的代价的边可以反转,所以再建一条反向边即可. 在 DAG 中,存在一个点可以到达所有的点的条 ...

  8. edge浏览器禁用搜索工具栏或七七八八的东西

    edge浏览器禁用搜索工具栏或七七八八的东西 在浏览器地址里输入: edge://flags/#edge-show-feature-recommendations 把"Show featur ...

  9. realtek高清晰音频管理器 WIN10

    在WIN10里已经改名了: Realtek Audio Console . 在安装realtek声卡驱动后,Realtek Audio Console 会自动安装.

  10. 网易面试:SpringBoot如何开启虚拟线程?

    虚拟线程(Virtual Thread)也称协程或纤程,是一种轻量级的线程实现,与传统的线程以及操作系统级别的线程(也称为平台线程)相比,它的创建开销更小.资源利用率更高,是 Java 并发编程领域的 ...