前言
自定义数据库结构实际上仅仅需要实现一个自定义的UserDetailsService;
1.数据库准备
CREATE TABLE `sys_users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(60) DEFAULT NULL,
`enable` tinyint(4) NOT NULL DEFAULT '1' COMMENT '用户是否可用',
`roles` text COMMENT '用户角色,多个角色之间用逗号隔开',
PRIMARY KEY (`id`),
KEY `username` (`username`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2.插入测试数据
INSERT INTO `springdemo`.`sys_users`(`id`, `username`, `password`, `enable`, `roles`) VALUES (1, 'admin', '123', 1, 'ROLE_ADMIN,ROLE_USER');
INSERT INTO `springdemo`.`sys_users`(`id`, `username`, `password`, `enable`, `roles`) VALUES (2, 'user', '123', 1, 'ROLE_USER');
3.编写User实体
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
public class SysUsers implements UserDetails {
private Long id;
private String userName;
private String password;
private String roles;
private boolean enable;
private List<GrantedAuthority> authorities;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public void setUserName(String userName) {
this.userName = userName;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return this.userName;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return this.enable;
}
public void setPassword(String password) {
this.password = password;
}
public String getRoles() {
return roles;
}
public void setRoles(String roles) {
this.roles = roles;
}
public boolean isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
public void setAuthorities(List<GrantedAuthority> authorities) {
this.authorities = authorities;
}
}
4.持久层准备
4.1准备pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
4.2配置数据库连接
spring.security.user.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/springDemo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
spring.datasource.username=root
spring.datasource.password=root
4.3启动类上加MapperScan
@MapperScan("com.demo.springsecuritydemo.mapper")
@SpringBootApplication
public class SpringSecurityDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringSecurityDemoApplication.class, args);
}
}
4.4编写映射接口
@Component
public interface UserMapper {
@Select("select * from sys_users where username = #{username}")
SysUsers findByUsername(@Param("username")String username);
}
5.编写MyUserDetailService
@Service
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//从数据库尝试获取该用户
final SysUsers user = userMapper.findByUsername(username);
//用户不存在 抛出异常
if (user == null) {
throw new UsernameNotFoundException("用户不存在");
}
//将数据库形式的roles解析成UserDetails的权限集
//AuthorityUtils.commaSeparatedStringToAuthorityList是spring-security提供的
//该方法用于将逗号隔开的权限集字符串切割成可用权限列表
//当然也可以自己实现,如用分号来隔开等,参考generateAuthorities
user.setAuthorities(AuthorityUtils.commaSeparatedStringToAuthorityList(user.getRoles()));
return user;
}
/**
* 自行实现权限的转换
*/
public List<GrantedAuthority> generateAuthorities(String roles) {
final ArrayList<GrantedAuthority> authorities = new ArrayList<>();
final String[] roleArray = roles.split(";");
if (roles != null && !"".equals(roles)) {
for (String role : roleArray) {
authorities.add(new SimpleGrantedAuthority(role));
}
}
return authorities;
}
6.绑定到资源授权的配置类
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailsService myUserDetailsService;
@Autowired
PasswordEncoder passwordEncoder;
/**
* 我们自定义配置认证用户
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService).passwordEncoder(passwordEncoder);
}