文章目录
回顾
前面通过《循序渐进学习spring security 第二篇,如何修改默认用户?》介绍了如何通过配置修改用户名和密码,循序渐进的从配置文件配置默认用户到从代码中通过内存的方式配置了登录用户名和密码,但是实际开发中,懂得了配置这些是没什么用的,毕竟所有用户数据都是存储在数据库中的,我们得从数据库中读取用户来进行登录的认证。前面通过《循序渐进雪spring security 第四篇,登录流程是怎样的?登录用户信息保存在哪里?》介绍了登录流程,介绍了登录过程中用户数据是做了哪些校验的,如果对登录流程还不熟悉的,建议翻看前面文章学习下。
源码下载 找到security-mybatis项目下载即可
如何从数据库中读取用户数据进行认证?
从数据库读取用户,目前比较流行的框架有mybatis,jpa,hibernate,jdbc,…,对于技术选型,大家项目中不懂如何选的可以在评论区留言,我可以给您个建议。当然,很多企业都有架构师,都不需要我们开发来选。我们选择mybatis
我们通过《循序渐进雪spring security 第四篇,登录流程是怎样的?登录用户信息保存在哪里?》的介绍了解到,登录过程中是从这段代码中获取用户系统中的用户的
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
this.prepareTimingAttackProtection();
try {
UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
if (loadedUser == null) {
throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation");
} else {
return loadedUser;
}
} catch (UsernameNotFoundException var4) {
this.mitigateAgainstTimingAttack(authentication);
throw var4;
} catch (InternalAuthenticationServiceException var5) {
throw var5;
} catch (Exception var6) {
throw new InternalAuthenticationServiceException(var6.getMessage(), var6);
}
}
也就是说,是通过对象UserDetailsService 调用了loadUserByUsername 方法,传入参数用户名,来获取系统中的用户UserDetails ,然后继续往下进行登录逻辑的校验
清楚了这个逻辑,接下来的事情就明白了,我们需要做3件事情:
1.创建一个类,实现了UserDetailsService 接口loadUserByUsername 方法,就能实现从数据库中获取用户
2.创建一个用户实体类,实现UserDetails 接口,在实现loadUserByUsername 方法时,返回这个用户的实体类
3.配置关联到UserDetailsService 的实现类
创建项目
创建工程 :security-mybatis
选择maven相关的依赖
为了方便大家copy,我这里也把依赖贴出来
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.70</version>
</dependency>
<!--mysql数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
创建实体类:User,实现接口UserDetails
public class User implements UserDetails {
private String password;
private String username;
private boolean accountNonExpired=true;
private boolean accountNonLocked=true;
private boolean credentialsNonExpired=true;
private boolean enabled;
private List<GrantedAuthority>authorities;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return accountNonExpired;
}
@Override
public boolean isAccountNonLocked() {
return accountNonLocked;
}
@Override
public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}
@Override
public boolean isEnabled() {
return enabled;
}
}
前面我们介绍登录流程时有介绍过用户信息的几个字段的校验,如果为FALSE,就会登录不通过,这里,我作为案例讲解就偷懒了下,默认将accountNonExpired,accountNonLocked,credentialsNonExpired 这几个字段值设为true,因为我的用户表里面没有这几个字段,而我的建表语句也是很简单
<!--用户表-->
CREATE TABLE `h_user` (
`username` varchar(50) NOT NULL,
`password` varchar(500) NOT NULL,
`enabled` tinyint(1) NOT NULL,
PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
INSERT INTO `h_user` (`username`, `password`, `enabled`) VALUES ('harry', '123456', '1');
INSERT INTO `h_user` (`username`, `password`, `enabled`) VALUES ('mike', '123456', '1');
创建mapper
@Mapper//指定这是一个操作数据库的mapper
public interface UserMapper {
@Select("select * from h_user where username=#{username}")
User findUserByUsername(String username);
}
创建UserDetailsServiceImpl类,实现接口UserDetailsService
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Resource
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User userByUsername = userMapper.findUserByUsername(username);
return userByUsername;
}
}
配置spring security 关联数据库
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
别忘了配置数据源
spring:
#数据库连接配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/harry?characterEncoding=utf-8&useSSL=false
username: root
password: xxx #xxx就是你的数据库密码
到这里,我们的配置基本上已经完成了。
接下来,我们在随便创建个Controller来测试下
@RestController
public class HelloController {
@RequestMapping("/sayHello")
public String sayHello(){
return "十年生死两茫茫,不思量,自难忘----苏轼,hello";
}
@RequestMapping("/home")
public String home(){
return "天生我材必有用,千金散尽还复来----李白,hello";
}
}
测试效果
启动项目,访问接口:http://127.0.0.1:8080/sayHello,因为还没有登录,此时,会自动跳转到登录页面,输入我们在数据库中的用户名和密码,点击登录就可以登录成功,接口能正常返回数据了。
源码下载 找到security-mybatis项目下载即可,记得自己改下数据库的配置再运行项目