Spring Security

1.Spring  Security是什么

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

2.为什么使用Spring Security

可以帮助进行认证和授权:

认证:就是用户登录的时候,检验用户的信息是否正确

授权:就是字面的意思,就像是每个用户又那些权限(vip1,vip2)

3.如何使用Spring Security

3.1引入依赖

        
            org.springframework.boot
            spring-boot-starter-security
        

3.2启动项目 ,控制台会出现登录密码。账号未user

Spring Security_第1张图片

可以通过配置文件来修改账号密码:

也可以通过配置类来修改账号密码:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        BCryptPasswordEncoder pe = new BCryptPasswordEncoder();
        String encode = pe.encode("123456");
        auth.inMemoryAuthentication()
                .passwordEncoder(pe)
                .withUser("gjc") //设置用户名
                .password(encode).roles("USER");//设置密码以及角色
    }

}

4.自定义表单登录

如果不直接使用框架自带的html页面的话,就需要我们配置页面比如:使用jsp,或者使用thymeleaf模板引擎

4.1自定义登录页面

Spring Security_第2张图片




    
    
    
    登录
    


用户名:
密码:

4.2修改配置类

Spring Security_第3张图片

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 这是配置自定义的信息
        http
                .formLogin().loginPage("/login.html")  //配置为自定义的登录页面
                .usernameParameter("myname")  //设置页面form表单的用户名参数
                .passwordParameter("mypwd") //设置页面form表单的密码参数
                .loginProcessingUrl("/userlogin") //登录路径和前台form登录接口路径保持一致
//                .defaultSuccessUrl("/")//登录成功跳转路径
                .and().authorizeRequests().antMatchers("/","userlogin","/login.html").permitAll()//设置哪些路径不需要拦截
                .anyRequest().authenticated()//除去不需要认证的路径的其它路径都需要认证
//                .and().exceptionHandling().accessDeniedPage("")//自定义没有权限的页面
                .and().csrf().disable(); //关闭csrf的保护
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        BCryptPasswordEncoder pe = new BCryptPasswordEncoder();
        String encode = pe.encode("123456");
        auth.inMemoryAuthentication()
                .passwordEncoder(pe)
                .withUser("gjc")
                .password(encode).roles("USER");
    }

}

5.通过数据库账号密码登录

Spring Security_第4张图片

Spring Security_第5张图片

如果需要根据数据库的账号密码进行登录,就需要替换掉原本的UserDetailsService,因为之前实在内存中查找账号密码,现在需要从数据库中查找。

5.1准备工作

依赖:



        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
        
            org.springframework.boot
            spring-boot-starter-security
        
        
        
            org.projectlombok
            lombok
        
        
        
            com.baomidou
            mybatis-plus-boot-starter
            3.4.2
        
        
        
            mysql
            mysql-connector-java
            8.0.31
        
        
        
            com.alibaba
            druid-spring-boot-starter
            1.2.6
        
    

mysql连接配置:properties

spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.username=root
spring.datasource.druid.password=root
spring.datasource.druid.url=jdbc:mysql://localhost:3306/qy168?serverTimezone=Asia/Shanghai

#配置mybatis plus驼峰关闭
mybatis-plus.configuration.map-underscore-to-camel-case=false
#控制台打印sql语句日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

实体类:

@Data
@TableName("tbl_user")
public class TblUser {
    @TableId(type = IdType.AUTO)
    private long id;
    private String username;
    private String password;
    private String headImg;
    private String phone;
    private String realname;
}

mybatis plus的mapper层和server层这里就不列举了,相信大家都会了

5.2替换UserDetailsService

替换UserDetailsService,重写其中的方法,从数据库中查询用户信息

@Service
public class MyUserDetailsService implements UserDetailsService {
    @Autowired
    private UserService userService;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //查询用户信息
        LambdaQueryWrapper query = new LambdaQueryWrapper<>();
        query.eq(TblUser::getUsername,username);
        TblUser tblUser = userService.getOne(query);
        //如果没有查询到用户信息就抛出异常
        if (Objects.isNull(tblUser)){
            throw new RuntimeException("用户名或密码错误");
        }
        //TODO 查询对应的权限信息
        //因为现在用户还没有权限模拟以下权限
        // 查询用户的权限信息并将其转换为GrantedAuthority对象列表
        List authorities = new ArrayList<>();
        // 例如,假设用户有ROLE_USER角色
        authorities.add(new SimpleGrantedAuthority("ROLE_USER"));

        //将数据封装为UserDetails对象
        //因为这个User实现了UserDetails,所以我们可以使用这个User实体类
        User user = new User(tblUser.getUsername(), tblUser.getPassword(), authorities);
        return user;
    }
}

测试:发现报错了

因为这里密码默认采用了一种PasswordEncoder密码校验的东西,如果要让密码是明文存储,需要在密码前加{noop}

真正开发肯定是不会用这种方式的,密码也不会明文存储。我们一般使用的SpringSecurity为我们提供的BCryptPasswordEncoder.

使用非常简单,只需要把BCryptPasswordEncoder注入到bean容器就行

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

}

测试:

@Test
    void text(){
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String encode = passwordEncoder.encode("123456");//对123456进行加密
        String encode1 = passwordEncoder.encode("123456");//对123456进行加密
        System.out.println(encode);
        System.out.println(encode1);
        //盐相同密文是不同的
        //比较
        boolean matches = passwordEncoder.matches("123456", "$2a$10$4IfzCQBjoxfmBGLg.SlnfOKwEBkuXDYBoEpU.8kUmBYF5WO.5zb42");
        boolean matches1 = passwordEncoder.matches("123456", "$2a$10$FDltmVxzybG9HNx6e1jBu.NvBLHM4QD0lmZVV98igMQ4TgOCOet.e");
        System.out.println(matches);
        System.out.println(matches1);

    }

运行结果:

Spring Security_第6张图片

那么我们只需要修改数据库的密码为加密之后的密码

再进行登录就可以了,这块在注册时就需要使用BcryptPasswordEncoder对密码加密存储到数据库中

6.前后端分离

6.1分析

登录:

1.需要自定义登录接口  -- 调用ProviderManager的方法进行认证 如果认证通过生成jwt -- 把用户信息存入redis中

2.自定义UserDetailsService -- 在这个实现类中查询数据库

校验:

1.定义jwt认证过滤器 -- 获取token -- 解析token获取其中的userid -- 从redis中获取用户信息 -- 存入SecurityContextHolder

6.2准备工作:

依赖:在之前依赖中新增


        
        
            org.springframework.boot
            spring-boot-starter-data-redis
        

        
        
            io.jsonwebtoken
            jjwt
            0.9.0
        

redis配置:

你可能感兴趣的:(spring,sql,java)