前言
自定義數據庫結構實際上僅僅需要實現一個自定義的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);
}