SpringSecurity-5-UserDetailsService与UserDetails接口(用户来源)

本文主要是介绍SpringSecurity-5-UserDetailsService与UserDetails接口(用户来源),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

欢迎你来看我的SpringSecurity系列文章,因为是系列文章,所以部分文章内容是有承前启后的关系

这个UserDetailsService接口是用户数据的来源,就是登录用户的数据从哪里来,是从数据库来?还是从你电脑的TXT文本上过来的,还是从其他地方,该接口会返回UserDetails接口的实例,而这个UserDetails接口,就是用户信息,因为用户信息除了username,password这些字段之外,不同项目会包含不同的信息,比如在我的项目中,用户登录之后会在用户信息中添加age,birthday等信息,所以spring定义了一个UserDetails接口,就是为了方便我们自定义字段的

任何实现了UserDetailsService接口的实现类,都可以作为认证数据的来源,只要把这个实现类的实例注入到spring容器中,SpringSecurity便可以自动发现并使用该实例

所以本篇文章将演示:用户shiwentian想访问test1,但是需要登录,用户输入帐号shiwentian,密码123456,通过UserDetailsService接口拿到该帐号的用户,匹配帐号密码,成功登陆,然后将用户的username,age,birthday等信息放到UserDetails接口实例,转换成json字符串,最终返回到前台页面,然后由前端发起请求访问test1,当然了,本文不会展示前端发送请求的代码

步骤1: 首先我们定义一个controller,里面包含一个方法

@RestController
public class AController {@RequestMapping("/test1")public String test1() {return "OK1";}
}

步骤2: 然后定义一个用户类,上文也说了,因为我们要返回给前端age和birthday,所以这个类必须我们自己实现UserDetails接口


public class TestUser implements UserDetails {// 注意,这个password是需要加密之后,再set到本类的,本文后续会有代码再次提示该注意事项private String password;// username是spring security默认的账号字段名字private String username;// 正是因为存在下面2个字段,所以我们需要自己实现UserDetails,spring自己提供了// 几个UserDetails接口的实现,但是我们要返回给前端age和birthday,所以不用spring的private int age;		private String birthday;@Overridepublic String getPassword() {return password;}@Overridepublic String getUsername() {return username;}// 注意:下面3个方法如果返回false,则spring security会登录失败并且在错误信息中提示"用户已失效"// 错误信息在AuthenticationFailureHandler接口的AuthenticationException.getMessage()方法中// 错误信息文章请参考本系列文章的第4章节:AuthenticationFailureHandler接口@Overridepublic boolean isAccountNonExpired() {// 本文为了演示,恒定写死返回truereturn true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;}// 如果此方法返回false,则spring security会登录失败并且在错误信息中提示"用户帐号已被锁定"// 错误信息在AuthenticationFailureHandler接口的AuthenticationException.getMessage()方法中// 错误信息文章请参考本系列文章的第4章节:AuthenticationFailureHandler接口@Overridepublic boolean isAccountNonLocked() {// 本文为了演示,恒定写死返回truereturn true;}// 省略了其他重写方法,省略了部分get/set方法,为了篇幅更短
}

步骤3: 接下来用户类有了,但是用户类里有一个比较特殊的字段,就是password,在spring security中,它要求我们先根据帐号,查询到这个用户,然后spring security自己拿着前端页面传递过来的密码进行一次加密,spring加密完前端密码之后,会用这个加密后的密码,和我们上述代码返回的TestUser类的password对比,所以这里遇到的问题就是:spring security需要知道加密方式是什么
spring是这样做的,如果容器中有PasswordEncoder接口实例,则直接使用该接口实例进行加密,如果容器中不存在PasswordEncoder接口实例,则系统直接报错,错误信息为:There is no PasswordEncoder mapped for the id "null",所以我们自己往容器中注入一个PasswordEncoder,代码如下:

@Service
public class TestPasswordEncoder extends BCryptPasswordEncoder {// 这种写法叫做Full Configuration Class
}

在这里我多说一下,上述中的TestPasswordEncoder 直接继承了spring自带的BCryptPasswordEncoder ,其实更简单的方法应该是下面这样的,在启动类或者某个@Service或者@Component等等这种类中使用@Bean注解

@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}// 写这个就不用写上面的TestPasswordEncoder了// 这种写法叫做Lite Configuration Class@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
}

我为什么要自己写一个TestPasswordEncoder 呢?主要是我突然想到了full模式和lite模式,也没什么,就是复习一下这两个模式而已。。。你也可以参考这篇ConfigurationClassUtils类复习一下,主要就是lite模式适用于已有的类,但是没有注入到容器中,例如本文中的BCryptPasswordEncoder

步骤4: 接下来实现UserDetailsService接口,用于查询登录的帐号密码是否正确


@Service
public class TestUserDetailsService implements UserDetailsService {// 上文已经注入了PasswordEncoder,所以我们直接注入到本类,当然,在代码里new一个也行,因为加密规则都相同,无所谓@Resourceprivate PasswordEncoder encoder;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {// 如果输入的帐号是shientian,则模拟从数据库查询出该账号的密码if ("shiwentian".equals(username)) {TestUser user = new TestUser();user.setUsername("史文天");user.setPassword(encoder.encode("123456"));// 模拟从数据库查询出密码user.setAge(28);user.setBirthday("1996-03-12");return user;}// 如果输入的帐号不是shiwentian,则直接返回null,表示没有该账号,此时spring security会提示帐号密码不匹配return null;
}

步骤5: 帐号密码正确,登录成功,将该人员信息返回给前端页面

public class TestReturnJsonValueHandler implements AuthenticationSuccessHandler {@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {// 主要注意一下getPrincipal方法,它返回的就是本文开头的TestUser类,也就是UserDetails接口的实现类Object testUser = authentication.getPrincipal();response.setContentType("application/json;charset=UTF-8");PrintWriter out=response.getWriter();ObjectMapper jsonObj = new ObjectMapper();String jsonString = jsonObj.writeValueAsString(testUser);out.write(jsonString);out.close();// authentication.getAuthorities();}
}

步骤6: 启动服务,浏览器输入http://localhost:8081/test1,此时会跳转到登录页面,输入帐号shiwentian,密码123456,则浏览器上显示该人员的Json字符串格式的信息

本文到此就结束了,在spring security中,有UserDetailsService接口是有几个实现类的,所以我们可以不自己实现,例如查询数据库可以直接使用JdbcUserDetailsManager,它就是一个UserDetailsService接口

下一篇文章:菜单接口权限

这篇关于SpringSecurity-5-UserDetailsService与UserDetails接口(用户来源)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1057389

相关文章

分布式锁在Spring Boot应用中的实现过程

《分布式锁在SpringBoot应用中的实现过程》文章介绍在SpringBoot中通过自定义Lock注解、LockAspect切面和RedisLockUtils工具类实现分布式锁,确保多实例并发操作... 目录Lock注解LockASPect切面RedisLockUtils工具类总结在现代微服务架构中,分布

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Spring Boot集成/输出/日志级别控制/持久化开发实践

《SpringBoot集成/输出/日志级别控制/持久化开发实践》SpringBoot默认集成Logback,支持灵活日志级别配置(INFO/DEBUG等),输出包含时间戳、级别、类名等信息,并可通过... 目录一、日志概述1.1、Spring Boot日志简介1.2、日志框架与默认配置1.3、日志的核心作用

破茧 JDBC:MyBatis 在 Spring Boot 中的轻量实践指南

《破茧JDBC:MyBatis在SpringBoot中的轻量实践指南》MyBatis是持久层框架,简化JDBC开发,通过接口+XML/注解实现数据访问,动态代理生成实现类,支持增删改查及参数... 目录一、什么是 MyBATis二、 MyBatis 入门2.1、创建项目2.2、配置数据库连接字符串2.3、入

Springboot项目启动失败提示找不到dao类的解决

《Springboot项目启动失败提示找不到dao类的解决》SpringBoot启动失败,因ProductServiceImpl未正确注入ProductDao,原因:Dao未注册为Bean,解决:在启... 目录错误描述原因解决方法总结***************************APPLICA编

深度解析Spring Security 中的 SecurityFilterChain核心功能

《深度解析SpringSecurity中的SecurityFilterChain核心功能》SecurityFilterChain通过组件化配置、类型安全路径匹配、多链协同三大特性,重构了Spri... 目录Spring Security 中的SecurityFilterChain深度解析一、Security

SpringBoot多环境配置数据读取方式

《SpringBoot多环境配置数据读取方式》SpringBoot通过环境隔离机制,支持properties/yaml/yml多格式配置,结合@Value、Environment和@Configura... 目录一、多环境配置的核心思路二、3种配置文件格式详解2.1 properties格式(传统格式)1.

Apache Ignite 与 Spring Boot 集成详细指南

《ApacheIgnite与SpringBoot集成详细指南》ApacheIgnite官方指南详解如何通过SpringBootStarter扩展实现自动配置,支持厚/轻客户端模式,简化Ign... 目录 一、背景:为什么需要这个集成? 二、两种集成方式(对应两种客户端模型) 三、方式一:自动配置 Thick

Spring WebClient从入门到精通

《SpringWebClient从入门到精通》本文详解SpringWebClient非阻塞响应式特性及优势,涵盖核心API、实战应用与性能优化,对比RestTemplate,为微服务通信提供高效解决... 目录一、WebClient 概述1.1 为什么选择 WebClient?1.2 WebClient 与

Java.lang.InterruptedException被中止异常的原因及解决方案

《Java.lang.InterruptedException被中止异常的原因及解决方案》Java.lang.InterruptedException是线程被中断时抛出的异常,用于协作停止执行,常见于... 目录报错问题报错原因解决方法Java.lang.InterruptedException 是 Jav