详解Spring Security怎么从数据库加载我们的用户

目录
  • 本章内容
  • 如何从数据库中读取用户对象?
    • 脱敏为什么没有生效?
  • 总结

本章内容

  • 如何从数据库中读取用户对象
  • 源码分析

如何从数据库中读取用户对象?

1前面我们分析认证的时候就会发现他在DaoAuthenticationProvider中就已经有从数据库中获取用户名和密码的。

public interface UserDetailsService {
   UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

意思是说我们只要重写这个类,就可以从我们所想要的地方获取用户信息。

那我们重写吧

public class MybatisUserDetailsService implements UserDetailsService, UserDetailsPasswordService {
	@Resource
	private UsersMapper usersMapper;
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		Users users = usersMapper.loadUserByUsername(username);
		if (null == users) {
			throw new UsernameNotFoundException(username);
		}
		return users;
	}
	@Override
	public UserDetails updatePassword(UserDetails user, String newPassword) {
		if (user instanceof Users users) {
			users.setPassword(newPassword);
			usersMapper.updateByPrimaryKeySelective(users);
		}
		return user;
	}
}

发现这里需要把spring security的users对象转换成我们所需要的users对象。比较麻烦。

小白: "为什么不直接使用spring security那里面的users对象呢?"

小黑: "我们自己实现users对象的话就可以在自定义。特别是权限这边,我们肯定是需要自定义users对象的,不能直接使用其内部的对象。"

然后我们直接继承UserDetails接口,然后自定义一些我们所需要的属性。说白了就是从内置users对象中拷贝一些代码出来。

小黑: "这里我故意留下了一个坑,如果你真的从内置的users对象里的话,你会发现一个问题。"

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Users implements Serializable, UserDetails {
    private Long id;
    private String username;
    private String password;
    private Boolean enabled;
    private Boolean accountnonexpired;
    private Boolean accountnonlocked;
    private Boolean credentialsnonexpired;
    private List<Roles> rolesList;
    private static final long serialVersionUID = 1L;
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        ArrayList<SimpleGrantedAuthority> authorities = new ArrayList<>();
        for (Roles roles : getRolesList()) {
            authorities.add(new SimpleGrantedAuthority(roles.getRole()));
        }
        return authorities;
    }
    @Override
    public boolean isAccountNonExpired() {
        return accountnonexpired;
    }
    @Override
    public boolean isAccountNonLocked() {
        return accountnonlocked;
    }
    @Override
    public boolean isCredentialsNonExpired() {
        return credentialsnonexpired;
    }
    @Override
    public boolean isEnabled() {
        return enabled;
    }
}

小白: "代码定义好了,但现在你要怎么加入到spring security中呢?让spring security主动调用我们自定义的类呢?"

小黑: "我们要使用自定义的类的话,无非是在DaoAuthenticationProvider里面设置。所以我们只要找到setUserDetailsService这个函数就行了。看一下有哪些方法调用了这个函数?"

看了一下发现这边调用了setUserDetailsService方法的。前面的UserDetailsService是对象是通过spring bean上下文面拿出来的。

那我们也可以效仿他的方式,在spring bean上添加我们的UserDetailsService Bean。

@Bean
public UserDetailsService userDetailsService() {
   return new MybatisUserDetailsService();
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
   return httpSecurity.authorizeHttpRequests()
         .anyRequest().authenticated()
         .and()
         .formLogin()
         .defaultSuccessUrl("/hello", true) // 认证成功后访问
         .permitAll() // 白名单
         .and()
         .logout()
         .logoutUrl("/logout")
         .logoutSuccessUrl("/login") // 注销成功后访问
         .clearAuthentication(true)
         .invalidateHttpSession(true)
         .and()
         .build();
}
@GetMapping("hello")
public HashMap<String, Object> hello(Authentication authentication) {
   HashMap<String, Object> map = new HashMap<>();
   Object principal = authentication.getPrincipal();
   String name = authentication.getName();
   map.put("principal", principal);
   map.put("name", name);
   return map;
}

小白: "停一下, 你数据库表结构呢? "

小黑: "我忘了, 我找找在哪可以抄"

在分析UserDetailsService的时候, 我们一般都要看看他的类族是怎样的, 结果发现可以偷懒的地方, 也就是表结构的位置

create table users(username varchar_ignorecase(50) not null primary key,password varchar_ignorecase(500) not null,enabled boolean not null);
create table authorities (username varchar_ignorecase(50) not null,authority varchar_ignorecase(50) not null,constraint fk_authorities_users foreign key(username) references users(username));
create unique index ix_auth_username on authorities (username,authority);

这段sql要改改, 否则mysql无法执行

结果发现, 就这...

我还不如自己设计呢

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for authorities
-- ----------------------------
DROP TABLE IF EXISTS `authorities`;
CREATE TABLE `authorities`  (
  `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `authority` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  UNIQUE INDEX `ix_auth_username`(`username` ASC, `authority` ASC) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for users
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users`  (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  `enabled` bit(1) NULL DEFAULT NULL,
  `accountNonExpired` bit(1) NULL DEFAULT b'1',
  `accountNonLocked` bit(1) NULL DEFAULT b'1',
  `credentialsNonExpired` bit(1) NULL DEFAULT b'1',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;

注意, 这里仅仅只是为了玩耍, 而非企业, 在企业中, 肯定不是这么设计的, 一般根据 RBAC 设计

小白: "这样就完成了?"

小黑: "完成了, 其他代码都是mybatis生成的, 简单"

启动, 访问 崩了

等下, spring security脱敏呢? 为什么这里可以输出密码?

分析源码看看

脱敏为什么没有生效?

通过源码分析,脱敏应该是认证成功之后的事情

大概看了下源码, ProviderManager有脱敏, 但是为什么不生效呢?

看这代码的意思, 是要我们在 Users 类上多添加一个接口CredentialsContainer

public class Users implements Serializable, UserDetails, CredentialsContainer {
	@Override
	public void eraseCredentials() {
        // 设置 password 为 null
		this.password = null;
	}
}

行, 前面的坑补上了。再试试

完美~~~

总结

记住UserDetailsService怎么自定义, 注意自定义的User需要实现哪些接口, 还有脱敏问题

以上就是详解Spring Security怎么从数据库加载我们的用户的详细内容,更多关于Spring Security数据库加载用户的资料请关注我们其它相关文章!

(0)

相关推荐

  • SpringBoot Security实现单点登出并清除所有token

    目录 需求 记录token 清除token 解决登出时长过长 需求 A.B.C 系统通过 sso 服务实现登录 A.B.C 系统分别获取 Atoken.Btoken.Ctoken 三个 token 其中某一个系统主动登出后,其他两个系统也登出 至此全部 Atoken.Btoken.Ctoken 失效 记录token pom 文件引入依赖 Redis数据库依赖 hutool:用于解析token <dependency> <groupId>org.springframework.boo

  • Idea中如何查看SpringSecurity各Filter信息

    目录 Filter和Filter Chain Idea Evalute Expression 创建工程 debug启动服务 evaluate expression 总结 Filter和Filter Chain SpringSecurity的认证逻辑是通过Filter Chain实现的,一个项目中Filter是链式执行,其中一环校验不通过,则可终止后续Filter以及Api的调用.     public void doFilter(ServletRequest request, ServletRe

  • SpringSecurity自定义Form表单使用方法讲解

    目录 背景 实验-HttpBasic 实验-自定义登录页面 实验-自定义登录接口 实验-自定义登录数据参数 实验-自定义登录失败.成功处理器 实验-自定义登录成功跳转页面 实验-自定义退出接口 背景 本系列教程,是作为团队内部的培训资料准备的.主要以实验的方式来体验SpringSecurity的各项Feature. 新建一个SpringBoot项目,起名springboot-security-form,核心依赖为Web,SpringSecurity与Thymeleaf. <dependencie

  • Spring Security实现添加图片验证功能

    目录 本章内容 思路 方案 怎么将字符串变成图片验证码? kaptcha这么玩 hutool这么玩 传统web项目 过滤器方式 认证器方式 总结下 前后端分离项目 基于过滤器方式 基于认证器方式 本章内容 Spring security添加图片验证方式,在互联网上面有很多这种博客,都写的非常的详细了.本篇主要讲一些添加图片验证的思路.还有前后端分离方式,图片验证要怎么去处理? 图片验证的思路 简单的demo 思路 小白: "我们从总体流程上看图片验证在认证的哪一个阶段?" 小黑: &q

  • Spring Security如何实现升级密码加密方式详解

    目录 本章内容 密码加密方式怎么升级? 升级方案源码 实战 第一种方式: Spring Bean 他是怎么自动升级到BCrypt加密方式的? 第二种方式: 多继承接口方式 第三种方式: HttpSecurity直接添加 本章内容 密码加密方式怎么升级? spring security底层怎么实现的密码加密方式升级? 密码加密方式怎么升级? 前面我们学过DelegatingPasswordEncoder类,但是不清楚他到底是做什么的,我也没讲的很清楚.所以呢,我们就重新再讲一讲它的另一个实际应用.

  • SpringSecurity导致SpringBoot跨域失效的问题解决

    目录 1.CORS 是什么 2.预检请求 3.三种配置的方式 3.1 @CrossOrigin 注解 3.2 实现 WebMvcConfigurer.addCorsMappings 方法 3.3 注入 CorsFilter 4.Spring Security 中的配置 5.这些配置有什么区别 5.1 Filter 与 Interceptor 5.2 WebMvcConfigurer.addCorsMappings 方法做了什么 5.2.1 注入 CORS 配置 5.2.2 获取 CORS 配置

  • 详解spring security四种实现方式

    spring security实现方式大致可以分为这几种: 1.配置文件实现,只需要在配置文件中指定拦截的url所需要权限.配置userDetailsService指定用户名.密码.对应权限,就可以实现. 2.实现UserDetailsService,loadUserByUsername(String userName)方法,根据userName来实现自己的业务逻辑返回UserDetails的实现类,需要自定义User类实现UserDetails,比较重要的方法是getAuthorities()

  • 一文详解Spring Security的基本用法

    目录 1.引入依赖 2.用户名和密码在哪里设置 3.UserDetailsService接口详解 3.1JdbcDaoImpl实现类 3.2InMemoryUserDetailsManager实现类 3.3自定义实现类实现UserDetailsService接口 4.如何修改登录页面 Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架, 提供了完善的认证机制和方法级的授权功能.是一款非常优秀的权限管理框架.它的核心是一组过滤器链,不同的功能经由不同的过滤器. 今天通

  • 详解Spring Security中权限注解的使用

    目录 1. 具体用法 2. SpEL 3. @PreAuthorize 最近有个小伙伴在微信群里问 Spring Security 权限注解的问题: 很多时候事情就是这么巧,松哥最近在做的 tienchin 也是基于注解来处理权限问题的,所以既然大家有这个问题,咱们就一块来聊聊这个话题. 当然一些基础的知识我就不讲了,对于 Spring Security 基本用法尚不熟悉的小伙伴,可在公众号后台回复 ss,有原创的系列教程. 1. 具体用法 先来看看 Spring Security 权限注解的具

  • 详解Spring Security如何在权限中使用通配符

    目录 前言 1. SpEL 2. 自定义权限该如何写 3. 权限通配符 4. TienChin 项目怎么做的 前言 小伙伴们知道,在 Shiro 中,默认是支持权限通配符的,例如系统用户有如下一些权限: system:user:add system:user:delete system:user:select system:user:update … 现在给用户授权的时候,我们可以像上面这样,一个权限一个权限的配置,也可以直接用通配符: system:user:* 这个通配符就表示拥有针对用户的

  • 详解Spring Hibernate连接oracle数据库的配置

    详解Spring Hibernate连接oracle数据库的配置 jdbc.properties文件配置如下  driverClassName=oracle.jdbc.driver.OracleDriver url=jdbc\:oracle\:thin\:@localhost\:1521\: database=OA username=oa password=oa initialSize=2 maxActive=10 maxIdle=2 minIdle=2 removeAbandoned=true

  • 详解Spring Security 中的四种权限控制方式

    Spring Security 中对于权限控制默认已经提供了很多了,但是,一个优秀的框架必须具备良好的扩展性,恰好,Spring Security 的扩展性就非常棒,我们既可以使用 Spring Security 提供的方式做授权,也可以自定义授权逻辑.一句话,你想怎么玩都可以! 今天松哥来和大家介绍一下 Spring Security 中四种常见的权限控制方式. 表达式控制 URL 路径权限 表达式控制方法权限 使用过滤注解 动态权限 四种方式,我们分别来看.  1.表达式控制 URL 路径权

  • 详解Spring Security中获取当前登录用户的详细信息的几种方法

    目录 在Bean中获取用户信息 在Controller中获取用户信息 通过 Interface 获取用户信息 在JSP页面中获取用户信息 在Bean中获取用户信息 Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (!(authentication instanceof AnonymousAuthenticationToken)) { String currentU

  • 详解springboot启动时是如何加载配置文件application.yml文件

    今天启动springboot时,明明在resources目录下面配置了application.yml的文件,但是却读不出来,无奈看了下源码,总结一下springboot查找配置文件路径的过程,能力有限,欢迎各位大牛指导!!! spring加载配置文件是通过listener监视器实现的,在springboot启动时: 在容器启动完成后会广播一个SpringApplicationEvent事件,而SpringApplicationEvent事件是继承自ApplicationEvent时间的,代码如下

  • 详解tomcat热部署和热加载的方法

    详解tomcat热部署和热加载的方法 我在项目开发过程中,经常要改动Java/JSP 文件,但是又不想从新启动服务器(服务器从新启动花时间),想直接获得(debug)结果.有两种方式热部署 和热加载: 1.热加载:在server.xml -> context 属性中 设置 reloadable="true" <Context docBase="xxx" path="/xxx" reloadable="true"/&

  • 详解Spring Security的Web应用和指纹登录实践

    前言 Java 开发人员在解决 Web 应用安全相关的问题时,通常会采用两个非常流行的安全框架,Shiro 和 Spring Security.Shiro 配置简单,上手快,满足一般应用的安全需求,但是功能相对单一.Spring Security 安全粒度细,与 Spring Framework 无缝集成,满足绝大多数企业级应用的安全需求,但是配置复杂,学习曲线陡峭. Spring Security 相对 Shiro 功能强大,并且 Spring Framework,Spring Boot,Sp

随机推荐