spring boot(学习笔记第十四课)
- Spring Security的密码加密,基于数据库认证
学习内容:
- Spring Security的密码加密
- 基于数据库认证
1. Spring Security的密码加密
- 如果用户的密码保存在数据库中是以明文保存,对于公司的安全将是灾难性的,哪个公司也不会允许用户数据使用明文保存。这里练习使用加密之后的密码进行认证。
注意,这样公司的数据库里面是没有用户的明文密码,即使数据库泄露,也不会暴漏用户的明文密码 - 实现密码加密
- 配置
passwordEncoder
@Bean PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(10); }
- 手动根据明文密码生成密文密码
bcrypt转换工具
注意,每次生成的密码都不一样,但是每个生成的都好用
- 使用生成的密文进行用户的创建。
@Bean UserDetailsService userDetailsService() { InMemoryUserDetailsManager users = new InMemoryUserDetailsManager(); users.createUser(User.withUsername("finlay_user") .password("$2a$10$uwwZ5EyWbFnnw3JG53rqQ.VJUm/.Pl9Ko1CUP5Aqc2kuBr2Bx7bc.") .roles("USER") .build());
- 再次进行认证。
- 配置
2. 基于数据库认证
以上练习了基于内存的认证,实际上,正式的系统开发都是使用数据库进行认证,在这里练习使用使用数据库的用户数据进行认证。这里使用postgresql
。
- 首先创建数据库需要的表
- 创建
USER
表CREATE TABLE "USER"( id int, username varchar(32), password varchar(255), enabled int, locked int, PRIMARY KEY(id) );
- 创建
ROLE
表CREATE TABLE "ROLE"( id int, name varchar(32), nameZh varchar(255), PRIMARY KEY(id) );
- 创建
USER_ROLE
表(user
和role
的关系表)CREATE TABLE "USER_ROLE"( id int, uid int, rid int, PRIMARY KEY(id) );
- 用户数据如下:
USER
表
ROLE
表
USER_ROLE
表
USER
和ROLE
的关系with uur as ( select * from "USER" u inner join "USER_ROLE" ur on u.id = ur.uid ) select username,namezh,name as rolename from uur inner join "ROLE" r on uur.rid = r.id
- 创建
- 引入必要的依赖
这里<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>3.0.3</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.9</version> </dependency>
repository
使用mybatis
,所以引入mybatis
的依赖包。 - 在
application.properties
定义数据库连接信息。spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.url=jdbc:postgresql://127.0.0.1:5432/springboot spring.datasource.username=finlay spring.datasource.password=123456
- 定义
mybatis
的interface
,以及xml
文件- 定义
User
和Role
的实体类@Data public class Role { private Integer id; private String name; private String nameZh; }
@Data public class User implements UserDetails { private Integer id; private String username; private String password; private Boolean enabled; private Boolean locked; private List<Role> roles; @Override public Collection<? extends GrantedAuthority> getAuthorities() { List<SimpleGrantedAuthority> authorities = new ArrayList<>(); for (Role role : roles) { authorities.add(new SimpleGrantedAuthority(role.getName())); } return authorities; } @Override public String getPassword() { return this.password; } @Override public String getUsername() { return this.username; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return !this.locked; } @Override public boolean isCredentialsNonExpired(){ return true; } @Override public boolean isEnabled(){ return this.enabled; } }
- 配置
mybatis
@Mapper public interface UserMapper { User loadUserByUserName(String usernam); List<Role> getUserRolesByUid(Integer id); }
- 配置
mybatis
的xml
配置文件<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.demo.repository.mybatis.UserMapper"> <select id="loadUserByUserName" resultType="com.example.demo.authentication.User"> select * from "USER" where username=#{username} </select> <select id="getUserRolesByUid" resultType="com.example.demo.authentication.Role"> select * from "ROLE" r, "USER_ROLE" ur where r.id=ur.rid and ur.uid=#{id} </select> </mapper>
- 定义
- 定义
UserDetailsService
注意,这里生成了@Service public class UserService implements UserDetailsService { @Autowired public UserMapper userMapper; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userMapper.loadUserByUserName(username); if (user == null) { throw new UsernameNotFoundException("username is not found"); } user.setRoles(userMapper.getUserRolesByUid(user.getId())); return user; } }
UserDetailsService
的bean
,所以spring boot security的
的认证处理,都会使用这个bean
- 整体的架构
- 测试认证结果