Spring Security是什么,以及如何在Spring Boot项目中整合Spring Security并且使用它,下面我们通过一个登录案例简单介绍一下Spring Security。

1.什么是Spring Security?

          在了解Spring Security之前,我们是不是应该先思考一个问题,我们自己写的web案例一般都需要先登录,之后登录之后才能访问其他页面,或者说我们不同的用户登录之后能进行的操作不同,比如系统管理员和普通用户所能操作的功能是有所区别的。那我们如何解决这个问题?

        不错,这时候我们就需要用到一些安全框架,比较Apache 旗下的Shiro、Spring家族中的Spring Security,Shiro相比Spring Security而言,比较简单易上手,不过我们这篇文章主要讲解Spring Security的简单应用。

        接着上面的话题,Spring Security提供了一组可用在Spring应用上下文中配置的Bean,充分的利用了Spring IOC、DI(依赖注入)、AOP(面向切面编程)的功能,提供了生命式的安全访问控制功能,提高了开发效率。

        Spring Security的本质就是一组过滤器链(16个),通过创建大量的filter和interceptor来进行请求的验证和拦截,以此来达到安全校验和鉴权的效果。

2.如何使用Spring Security?

        要使用Spring Security很简单,我们只需要引入Spring Security 的相关依赖,就可以得到一个Spring Security的简单示例。

创建Spring Boot项目 ,引入相关的依赖:


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

         <!--lombok依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

          <!--mysql依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

         <!--mybatis-plus依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1.tmp</version>
        </dependency>

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

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

配置yaml文件,主要配置数据源:

server:
  #配置服务端口号
  port: 8081  
spring:
  datasource:
    #配置数据库驱动
    driver-class-name: com.mysql.cj.jdbc.Driver  
    #配置数据库地址,务必加上时区
    url: jdbc:mysql://localhost:3306/yeb?useUnicode=true%&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    #数据库账户名称
    username: root
    #数据库密码
    password: XXXXX

然后启动Spring Boot项目,你会发现,咦,我明明没有编写登录页面,为什么它需要我登录?

没错,我们的Spring Security已经生效了,尽管我们什么也没做,只是引入了一个依赖而已,这是Spring Security的默认行为,只要我们添加了Spring Security的依赖,后续我们的所有操作都必须要通过它的验证才能继续。

它的账户是user,密码在我们后端控制台,每次生成的密码都是随机的,我们需要到后端控制台复制密码。

输入用户名,密码,就可以跳转到我们原来的页面。

 

 通过这个简单的使用, 你现在是不是对Spring Security有了大概的认识了。

3.Spring Security 的进阶使用,UserDetailsService的详解。

        我们当然不是只能使用它提供给我们的登录页面,我们可以通过相关的配置,将它的登录页面,替换为我们本来的的登录页面。        

 当我们需要自定义它的验证逻辑时,我们就需要来实现UserDetailsService这个接口

        点开它我们发现它里面只有一个方法,并且这个方法的作用是通过用户名加载用户,用户名怎么来的,看见后面的参数了么,它就是前端传递过来的用户名称,而且返回一个UserDetails的一个类,那这个类又是什么呢?,我们继续点开看看。

         点开这个类之后,我们发它仍然是一个接口,并且提供了很多方法,接口意味着我们要想使用它是不是就得现实现它,说明UserDetails在Spring Security中已经有了一个实现类了,接下来我们继续寻找UserDetails的实现类,并且观察它的实现类。

 我们ctrl+alt 点击UserDetails,就可以看到它的实现类,我们发现它确实存在一个实现类,并且类名为User,我们要注意把这个User区分开,这是Spring Security提供的User,同样的我们点开观察它。

 这个类里面的东西很多,我就不全部截图啦,大家可以自己点开看一下。总之,这个实现类User的意思大概就是根据客户端传递过来的用户名,它会去查询数据库,并且返回查到的相应信息,包括密码、用户名、权限信息、是否可用,账户是否失效等等。

 

 我们在回到UserDetailsService这个类,我们发现它抛出了一个异常,这个异常就是没有查询到数据时,它就会抛出这个异常。

4.PasswordEncoder详解。

        要实现Spring Security的自定义验证流程,我们除了实现USerDetailsService这个接口,我们还需要实现PasswordEncoder。当我们没有进行任何配置的时候,Spring Security它已经自带了一个实现了PasswordEncoder的实例,这就是我们刚刚运行时,控制台打印密码是那么一长串字符的原因。

        PasswordEncoder接口包含三个方法,如下:

 PasswordEncoder的实现类很多,每一个实现类都代表一种加密算法,官方推荐我们使用BCryptPasswordEncoder这种算法。

 大家也可以ctrl+alt点开看一看里面的内容,

 这里我们可以通过一个测试类来测试它的加密效果:


        //创建BCryptPasswordEncoder对象
        PasswordEncoder pe=new BCryptPasswordEncoder();

        String encode = pe.encode("123456");//调用encode方法加密,得到加密后的字符串
        System.out.println("加密后的密码 = " + encode);

        boolean matches = pe.matches("123456", encode);//调用matches方法匹配原密码和加密之后的密码
        System.out.println("原密码与加密后的密码是否相等 = " + matches);

 运行结果如上,通过这个小例子是不是对PasswordEncoder接口的使用有了更加深入的了解。

5.自定义登录登录逻辑

        了解了UserDetailsService和PasswordEncode之后,我们是不是就能自定义登录逻辑了,

现在我们回顾一下,给大家三分钟回想一下UserDetailsService是干啥的,有哪些方法,通过它我们可以干些啥,PasswordEncoder的方法及作用,可以用在什么场景,大家想一想,思考一下。

        在实现我们的自定义登录逻辑之前,我们的Spring Securit要求我们进行自定义登录逻辑时,我们的容器中必须有一个PasswordEncoder的实例存在,所以我们不能想上面那个例子一样直接用new的方式,我们需要写一个配置类,将它注入到容器当中。

代码如下:

@Configuration
public class SecurityConfig {

    @Bean
    public PasswordEncoder getpw(){
        return new BCryptPasswordEncoder();
    }
}

            接下来创建一个类去实现UserDetailsService接口,重写UserDetails方法,我们在serve层创建一个类UserDetailsServiceImpl去实现UserDetailsService接口,并且重写UserDetails方法。如图。

 OK,现在想一想我们应该做什么,它只有这个方法,这个方法有什么用。

具体如下:

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private PasswordEncoder pe;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //1.查询数据库判断用户名是否存在,如果不存在则抛出异常UsernameNotFoundException
                //怎么查数据库?这应该都会吧,我这里就不弄查数据库的部分了,节省时间,写几个小时了,这里我们就自己造一个数据吧,
                //假设我们从数据中查到的用户名为YangJunDong,我们直接判断就是
                if(!"YangJunDong".equals(username)) { //注意这个username是传递过来的参数,也就是前端输入框中的名字
                    throw new UsernameNotFoundException("用户名不存在!");
                }
        //2.将查询出来的密码(数据库中已加密的密码)进行解析,或者直接放到实现类的构造函数中?
                /*
                这里咱也不查数据库了,自己造一个密码吧,但是这个密码是数据库中的,我们得造一个加密的密码
                之前写的配置类管用了吧,我们直接Resource注入进来就好了
                 */
                String password = pe.encode("123");
        //通过数据库查到密码之后怎么做?我们这里采用直接放到到实现类(UserDetailsService的最终实现类是啥来着)的构造函数中,代码如下
                return new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList( "admin" ));
                //这里的三个参数,前两个用户名密码,不必多说,但是第三个是权限信息,同样的我们没查数据库,也只能造一个,使用AuthorityUtils工具类中
               //的commaSeparatedStringToAuthorityList方法,给其设置权限,我设置的权限是admin的权限,当然也可以短号隔开设置多个权限,一个人也存有多种权限的情况的
    }
}

      OK,到这里我们就成功自定义了登录逻辑,现在在次运行项目,然后我们会发现,控制台居然没有打印密码了,说明我们已经更改掉了它的默认方式,输入我们从数据库(自定义)的账号和密码。

 登录成功!!!

 那如果我们输出错误的密码,或者错误的用户名呢?

 OK,可以看到输入错误的信息是无法通过验证的。

以上就是这篇文章的内容了,这篇文章主要说了Spring Security的作用,以及UserDetailsService和PasswordEncoder接口的作用和使用方法,并且通过这个两个接口自定义了登录逻辑,也就是让它去查数据库,实打实的来,而不是用它默认的方法生成账户和密码,如果有错误的地方请大家指正。

后续会陆续更新自定义登录页面(将登录页面换成我们自己的登录页面)和Spring Security的其他功能。