首页 > 其他分享 >阐述Spring Security概念及其运用于实战

阐述Spring Security概念及其运用于实战

时间:2024-06-21 23:00:04浏览次数:22  
标签:实战 登录 Spring 配置 用户 认证 Security public

Spring Security(安全校验)

1. 概述

Spring Security是Spring项目组提供的安全服务框架,核心功能包括认证授权.为系统提供了声明式安全访问控制功能,减少了为系统安全而编写大量重复代码的工作.
在如今开发模式中,Spring Security已经成为Java程序员必备的一项技术,简化认证和授权开发的首选项,
其核心为认证和授权,我们先来了解一下何为认证和授权,理解其概念.

2. 认证

认证是指系统判断用户的身份是否合法,合法可继续访问,不合法则会拒绝访问.在生活中我们很常见认证的方式,例如人脸识别认证,指纹认证,用户名密码的登录,手机短信的登录等方式
认证的目的是保护系统的隐私数据和资源,用户的身份合法 才能访问资源.
注: SpringSecurity的依赖为(基于Spring Boot)

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

2.1 内存认证

内存认证的概念,及用户的数据存放在内存当中,数据在代码中写死,项目启动便加载到内存当中.代码如下

@Configuration
public class SpringSecurityConfig{

		@Bean
    public UserDetailsService userDetailsService(){
    //1.创建内存管理对象
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
	//2.创建权限对象
        UserDetails user1 = User.withUsername("zhangsan").password("123").authorities("admin").build();
        UserDetails user2 = User.withUsername("lisi").password("123").authorities("admin").build();
	//3.封装到manager当中
        manager.createUser(user1);
        manager.createUser(user2);
        return manager;
    }
}

这种认证方式很明显,不灵活,代码写死,用户信息仅有代码所包含部分.这不符合我们的业务开发,应该连接于数据库.所以Spring Security提供了另一套配置.我们需要创建一个配置类去实现UsersDetailsService接口.(这里我使用的是Mybatis-Plus去操作数据库)
代码如下:

@Service
public class MyUserDetailService implements UserDetailsService {

    @Autowired
    private UsersMapper usersMapper;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //1.查询数据库,是否存在对象
        Users users = usersMapper
        .selectOne(new QueryWrapper<Users>().lambda()
                .eq(Users::getUsername, username));
     
        //2.判断用户是否为空
        if(users == null){
            //2.1.1 为空直接返回
            return null;
        }
        //3.封装成userDetails对象
        UserDetails userDetails = User.withUsername(users.getUsername())
                .password(users.getPassword())
                .authorities("admin")
                .build();
        //5.返回
        return userDetails;
    }
}

2.2 密码编码

为了数据的安全性,通常我们存储到数据库的密码是经过转码的,即密文存储,所以我们需要配置转码的配置类,校验时才能检查对应的密码是否一致
Spring Security提供了BCryptPasswordEncoder编码配置类,我们注入一下即可.

/**
     * 密码解码配置
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

2.3 认证成功与失败的处理

当认证成功之后,我们可能要对用户做一些信息上的配置或者其他的调整,需要介入java代码,同理失败也得控制用户的信息,防止用户恶意破坏信息.
我们需要配置SecurityFilterChain,由名字也可知道这是经过SpringSecurity框架的执行链.我们可以在这配置我们的业务需求.代码如下(包含前端路径的可自行配置,这里我使用的是thymeleaf,在resource下创建templates目录,编写对应页面就可)
注: 别忘了配置第二步允许静态资源的访问

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        //1.配置登录表单
        httpSecurity.formLogin(form ->{
            form.loginPage("/login.html") //自定义登录页面
                    .loginProcessingUrl("/login")   //登录路径,表单向该路径提交,提交后自动执行MyUserDetailService的方法
                    .usernameParameter("username")  //表单中用户名项
                    .passwordParameter("password")  //表单中的密码项
                    .successHandler(new MyLoginSuccessHandler())    //登录成功跳转页面
                    .failureHandler(new MyLoginFailHandler());   //登录失败跳转页面
        });
        //2.配置需要认证和不需要认证的资源
        httpSecurity.authorizeHttpRequests(resp->{
            resp.requestMatchers("/login.html","/fail.html").permitAll(); //不需要认证的资源
            resp.requestMatchers("/css/*.css","/js/*.js","/img/**").permitAll();    //静态资源
            resp.anyRequest().authenticated();  //其余所有请求都需要认证
        });
        //3.关闭csrf防护(若不关闭资源无法访问)
        httpSecurity.csrf(csrf->{
            csrf.disable();
        });
}

认证成功的处理器

public class MyLoginSuccessHandler implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        //拿到登录用户的信息
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();

        System.out.println("用户名:"+userDetails.getUsername());
        System.out.println("登录之后的其余操作");
        //重定向到主页
        response.sendRedirect("/main");
    }
}

认证失败的处理器

public class MyLoginFailHandler implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        System.err.println(exception.getMessage());
        System.out.println("登录失败");
        response.sendRedirect("/fail.html");
    }
}

2.4 退出登录

用户需要退出登录时,我们需要清除他的会话信息及授权信息.配置如下(依旧配置在上述配置类SpringSecurityConfig的方法当中)

//配置退出登录功能
        httpSecurity.logout(out->{
//                out.logoutUrl("/logout")
            out.logoutSuccessHandler(new MyLoginLogOutSuccessHandler())
                    .invalidateHttpSession(true)    //清除session记录,默认为true
                    .clearAuthentication(true);    //清除授权记录,默认为true
        });

2.5 记住我

在许多登录场景当中,往往会有记住我这个选项.可以在一段时间内记住用户的登录信息,用户下次访问时便可以不再需要登录.我们可以思考一下怎么去做到这个事情.大家应该都接触过JWT令牌,对token字段我们并不陌生.我们可以在用户使用记住我这个功能时,生成一个Token令牌,保存到数据库当中,下次用户再来访问我们去数据库查询是否有这样一个Token即可.
SpringSecurity帮我们实现了这样一个功能,需要我们配置一下即可.其功能演示大概为:

首先我们得有这样一个存放token的表,利用SpringSecurity配置生成表(别忘了在配置文件中配置DataSource哦)

@Configuration
public class RememberMeConfig {
    @Autowired
    private DataSource dataSource;
    //生成令牌
    @Bean
    public PersistentTokenRepository getPersistentTokenRepository(){
        // 为Spring Security 自带的令牌控制器设置数据源
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        // 开启自动建表,第一次启动时需要,第二次就注释掉
//        jdbcTokenRepository.setCreateTableOnStartup(true);
        //返回
        return jdbcTokenRepository;
    }
}

注: 第一次启动运行时可以直接这样写,第二次启动记得把jdbcTokenRepository.setCreateTableOnStartup(true);给注释掉,若忘记啦也没有关系,控制台会报错(表已经存在),根据原因我们再来处理也可

再回到SpringSecurityConfig当中,将这个配置类生效

//注入这两个类
	@Autowired
    private PersistentTokenRepository persistentTokenRepository;
    @Autowired
    private MyUserDetailService myUserDetailService;
//配置记住我
        httpSecurity.rememberMe(remember->{
            remember.tokenRepository(persistentTokenRepository) //配置持久化token仓库
                    .userDetailsService(myUserDetailService)	//配置权限处理对象,即认证逻辑对象
                    .tokenValiditySeconds(30); //配置token的保持时间,即多久以后失效
        });

标签:实战,登录,Spring,配置,用户,认证,Security,public
From: https://blog.csdn.net/m0_65013257/article/details/138972430

相关文章

  • 基于SpringBoot+Vue的网上花店系统设计与实现(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示项目运行截图技术框架后端采用SpringBoot框架前端框架Vue可行性分析系统测试系统测试的目的系统功能测试数据库表设计代码参考数据库脚本为什么选择我?获取源码前言......
  • 【愚公系列】《短视频生成与剪辑实战》006-用Al文案生成视频
    ......
  • 基于SpringBoot+Vue的小学生课外知识学习网站系统设计与实现(源码+lw+部署文档+讲解等
    文章目录前言详细视频演示项目运行截图技术框架后端采用SpringBoot框架前端框架Vue可行性分析系统测试系统测试的目的系统功能测试数据库表设计代码参考数据库脚本为什么选择我?获取源码前言......
  • 基于Springboot的原创歌曲分享平台(有报告)。Javaee项目,springboot项目。
    演示视频:基于Springboot的原创歌曲分享平台(有报告)。Javaee项目,springboot项目。项目介绍:采用M(model)V(view)C(controller)三层体系结构,通过Spring+SpringBoot+Mybatis+Vue+Maven+Layui+Elementui来实现。MySQL数据库作为系统数据储存平台,实现了基于B/S结构的Web系统......
  • java干货 spring aop的理解和使用
    文章目录一、AOP概念1.1aop思想1.2aop应用场景二、aop如何使用2.1八个核心名词2.2代码实现一、AOP概念1.1aop思想APO(面向切面编程)是一种编程思想,它通过将通用的横向关注点(日志、事务、权限控制等)与业务逻辑分离,实现解耦,使得代码更易于维护。核心......
  • nodejs从基础到实战学习笔记-模块化、包
    二、模块化2.1什么是模块化模块化是指解决一个复杂问题时,自顶向下逐层把系统划分成若干模块的过程。对于整个系统来说,模块是可组合、分解和更换的单元。2.1.1把代码进行模块化拆分的好处提高了代码的复用性提高了代码的可维护性可以实现按需加载•如果程序设计的规......
  • Python统计实战:一题搞定一元线性回归的回归系数、显著性及预测值计算
    为了解决特定问题而进行的学习是提高效率的最佳途径。这种方法能够使我们专注于最相关的知识和技能,从而更快地掌握解决问题所需的能力。(以下练习题来源于《统计学—基于Python》。联系获取完整数据和Python源代码文件。)练习题随机抽取10家航空公司,对其最近一年的航班准点率......
  • Python统计实战:一题搞定一元线性回归分析、模型诊断分析
    为了解决特定问题而进行的学习是提高效率的最佳途径。这种方法能够使我们专注于最相关的知识和技能,从而更快地掌握解决问题所需的能力。(以下练习题来源于《统计学—基于Python》。联系获取完整数据和Python源代码文件。)练习题下面是来自R语言的anscombeh数据集(前3行和后3行......
  • Python统计实战:一题搞定双因子方差分析(交互效应分析)
    为了解决特定问题而进行的学习是提高效率的最佳途径。这种方法能够使我们专注于最相关的知识和技能,从而更快地掌握解决问题所需的能力。(以下练习题来源于《统计学—基于Python》。联系获取完整数据和Python源代码文件。)练习题城市道路交通管理部门为研究不同路段和不同时段......
  • SpringBoot配置Druid连接池
    简介:    连接池的作用是为了提高性能,将已经创建好的连接保存在池中,当有请求来时,直接使用已经创建好的连接对Server端进行访问。这样省略(复用)了创建连接和销毁连接的过程(TCP连接建立时的三次握手和销毁时的四次握手),从而在性能上得到了提高。Druid是一个JDBC组件,它包括三部......