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引入依赖

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

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

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

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

@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自定义登录页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>登录</title>
    <style>

    </style>
</head>
<body>
<form action="/userlogin" method="post">
    用户名:<input type="text" name="myname">  <!--name=myname注意后台需要配置这个名字-->
    <br/>
    密码:<input type="password" name="mypwd"> <!--name=mypwd注意后台需要配置这个名字-->
    <br/>
    <input type="submit" value="login">
</form>
</body>
</html>

4.2修改配置类

@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.通过数据库账号密码登录

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

5.1准备工作

依赖:

<dependencies>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--spring security-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--mp-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>
        <!--druid连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.6</version>
        </dependency>
    </dependencies>

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<TblUser> query = new LambdaQueryWrapper<>();
        query.eq(TblUser::getUsername,username);
        TblUser tblUser = userService.getOne(query);
        //如果没有查询到用户信息就抛出异常
        if (Objects.isNull(tblUser)){
            throw new RuntimeException("用户名或密码错误");
        }
        //TODO 查询对应的权限信息
        //因为现在用户还没有权限模拟以下权限
        // 查询用户的权限信息并将其转换为GrantedAuthority对象列表
        List<GrantedAuthority> 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);

    }

运行结果:

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

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

6.前后端分离

6.1分析

登录:

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

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

校验:

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

6.2准备工作:

依赖:在之前依赖中新增


        <!--redis依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!--jwt依赖-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>

redis配置:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值