SpringSecurity权限管理框架系列(二)-Spring Security框架实现用户登录认证流程详解

2022-06-15 09:46:31

1、Spring Security登录认证的核心

Spring Security框架完成用户登录认证的核心就在与org.springframework.security.core.userdetails包下的UserDetailsService接口

2、UserDetailsService接口详解

2.1 UserDetailsService接口的定义

UserDetailsService接口只有一个抽象方法就是loadUserByUsername(String username),
在这里插入图片描述
UserDetailsService接口的返回值是UserDetails接口, 这又是一个接口,Spring Security框架提供了它的实现类org.springframework.security.core.userdetails包下的User类对象
在这里插入图片描述

2.2 UserDetailsService接口的已有实现类有哪些

我们再看看UserDetailsService接口提供的默认的实现类

  • JdbcDaoImpl(还有一个子类JdbcUserDetailsManager)
  • InMemoryUserDetailsManager
    在这里插入图片描述
    在这里插入图片描述
2.2.1 UserDetailsService接口的实现类JdbcDaoImpl的实现

我们在分别看看UserDetailsService的实现类JdbcDaoImplInMemoryUserDetailsManager都是怎么实现这个loadUserByUsername(String username)方法的
在这里插入图片描述
我们在分别看看UserDetailsService的实现类JdbcDaoImpl中loadUserByUsername(String username)方法的实现过程
在这里插入图片描述
下图主要就是验证一下createuserDetails方法的返回值是不是一个User对象,没有什么具体含义。
在这里插入图片描述

2.2.2 UserDetailsService接口的实现类InMemoryUserDetailsManager的实现

看看InMemoryUserDetailsManager类的loadUserByUsername(String username)方法的具体实现
在这里插入图片描述
通过以上的源码解读, 我们可以大胆猜测一下一个是不是只要我们在我们自己的项目中定义一个自定义的实现类实现这个UserDetailsService,就可以完成我们自定义的登录认证逻辑, 接下来我们自己写一个实现类来尝试一下。

3、自定义实现类实现UserDetailsService接口

自定义实现类MyUserDetailsServiceImpl

packagecom.yige.service.impl;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.security.core.authority.AuthorityUtils;importorg.springframework.security.core.userdetails.User;importorg.springframework.security.core.userdetails.UserDetails;importorg.springframework.security.core.userdetails.UserDetailsService;importorg.springframework.security.core.userdetails.UsernameNotFoundException;importorg.springframework.stereotype.Service;@ServicepublicclassMyUserDetailsServiceImplimplementsUserDetailsService{privatestaticfinalString USERNAME="test";privatestaticfinalString PASSWORD="test";@OverridepublicUserDetailsloadUserByUsername(String userName)throwsUsernameNotFoundException{if(!USERNAME.equals(userName)){thrownewUsernameNotFoundException("用户名不存在");}UserDetails userDetails=newUser(USERNAME,
                PASSWORD,AuthorityUtils.commaSeparatedStringToAuthorityList("admin,common"));return userDetails;}}

重启项目看看,能不能生效。

登录输入用户名"test", 密码"test",发现页面刷新了一下又回到登录页面了, 怎么回事?
在这里插入图片描述
检查了一下后台程序,发现后台报错了,没有使用任何的PasswordEncoder,我们输入的密码没有用加密工具进行加密

在这里插入图片描述
Spring Security其实已经给我们提供了很多的PasswordEncoder, 我们来看一下
org.springframework.security.crypto.password包下有一个PasswordEncoder接口,看看他的实现类
在这里插入图片描述
所有这里就很简单了啊,两种方式可以搞定:

  • 我们只需要在我们的项目里面整一个Spring Security的配置类,把这个PasswordEncoder的任意一个我们需要用来加密密码的实现类的Bean注入到容器里面,就可以直接拿来使用
  • 我们也可以自己自定义密码加密的实现类实现PasswordEncoder接口, 注入Bean到容器

这里我们采用第一种方式,人家已经实现了, 不需要重复造轮子,当然如果你确信你自己造的轮子更好就可以用你自己的。

packagecom.yige.config;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.security.config.annotation.SecurityBuilder;importorg.springframework.security.config.annotation.web.WebSecurityConfigurer;importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;importorg.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;@ConfigurationpublicclassSecurityConfigextendsWebSecurityConfigurerAdapter{@BeanpublicBCryptPasswordEncodergetPasswordEncoder(){returnnewBCryptPasswordEncoder();}}

修改MyUserDetailsServiceImpl类如下:

packagecom.yige.service.impl;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.security.core.authority.AuthorityUtils;importorg.springframework.security.core.userdetails.User;importorg.springframework.security.core.userdetails.UserDetails;importorg.springframework.security.core.userdetails.UserDetailsService;importorg.springframework.security.core.userdetails.UsernameNotFoundException;importorg.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;importorg.springframework.stereotype.Service;/**
 * @Author: karma
 * @Date: 2022/3/21 0021 - 03 - 21 - 11:20
 * @Description: com.yige.service.impl
 * @version: 1.0
 */@ServicepublicclassMyUserDetailsServiceImplimplementsUserDetailsService{privatestaticfinalString USERNAME="test";privatestaticfinalString PASSWORD="test";@AutowiredprivateBCryptPasswordEncoder passwordEncoder;@OverridepublicUserDetailsloadUserByUsername(String userName)throwsUsernameNotFoundException{if(!USERNAME.equals(userName)){thrownewUsernameNotFoundException("用户名不存在");}returnnewUser(userName, passwordEncoder.encode(PASSWORD),AuthorityUtils.commaSeparatedStringToAuthorityList("admin,common"));}}

重启项目再次测试。

登录输入用户名"test", 密码"test",确认登录,

在这里插入图片描述
页面跳转到http://localhost:8080,说明我们的登录认证成功了。以上测试说明我们自定义的登录认证逻辑生效了,

4、测试结论

由以上测试我们可以得出结论,当我们自定义实现了UserDetailsService逻辑并注入bean到容器之后, 项目再次启动之后,在进行登录认证的时候就会使用我们自定义的逻辑来进行处理, 不会在使用Spring Security框架默认的逻辑进行认证处理。

5、下一节内容

当前我们的实现都是把用户名、密码、权限都是硬编码在我们自己的代码中, 这样肯定是不行的, 下一节我们着重说说怎么让我们自定义的登录认证跟我们的数据库搭配使用,从数据库中获取用户的数据信息来完成登录认证的过程。

  • 作者:嫣夜来
  • 原文链接:https://blog.csdn.net/qq_41865652/article/details/123631091
    更新时间:2022-06-15 09:46:31