首先是引入依赖

        <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. Jenkins通过脚本进行自动发布

    编写以下脚本: ------------------------------------------------------------------------------------- #!/bin ...

  2. U-Boot命令使用

    帮助命令 help 所有命令提示: h ? help 某一条命令提示: ? 命令名 help 命令名 信息查询命令 bdinfo 查看板子信息: => bdinfo arch_number = ...

  3. python获取豆瓣电影TOP250的所有电影的相关信息

    参考文档:https://weread.qq.com/web/reader/37132a705e2b2f37196c138k98f3284021498f137082c2e 说明:我才接触网络爬虫,在看 ...

  4. 从零开始写 Docker(十七)---容器网络实现(中):为容器插上”网线“

    本文为从零开始写 Docker 系列第十七篇,利用 linux 下的 Veth.Bridge.iptables 等等相关技术,构建容器网络模型,为容器插上"网线". 完整代码见:h ...

  5. CF1815

    CF1815 Div. 1 确实难,Virtual Contest 上只完成了两道题,想出来了三道题. A. Ian and Array Sorting 秒切题--考虑将前 \(n - 1\) 个数变 ...

  6. Java JVM——10.对象实例化内存布局与访问定位

    对象实例化 对象创建方式 ★ new:最常见的方式.单例类中调用getInstance的静态类方法,XXXFactory的静态方法. ★ Class的newInstance方法:在JDK9里面被标记为 ...

  7. 小米 红米 Redmi 屏幕录制默认参数设置

    小米 红米 Redmi 屏幕录制默认参数设置 视频画质:16Mbps. 帧数:60fps.

  8. redis 远程连接

    redis-cli -h host -p port -a password -h 服务器地址 -p 端口号 -a 密码

  9. 《Android开发卷——程序自动登录》

    Android程序的自动登录功能 因为是公司的项目,所以这里不方便说出项目名称,这里就说我在做这个项目中用到的一些功能或者叫技术问题吧. 咱们经常用的Android程序中有一个情况,就是当你第一次注册 ...

  10. 三月二十六日 安卓打卡app开发日志

    今天上午 将打卡逻辑代码优化了一下 之后每天就只可以打卡一次了 public static String daka(String time_s, String time_e, String text, ...