SpringSecurity连接数据库操作如下:
- 创建表结构
-- 用户表
CREATE TABLE `sys_user`(
`id` INT NOT NULL AUTO_INCREMENT,
`username` VARCHAR(255) NOT NULL,
`password` VARCHAR(255) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
-- 角色表
CREATE TABLE `sys_role`(
`id` INT NOT NULL,
`code` VARCHAR(255) NOT NULL,
`name` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
-- 中间表
CREATE TABLE sys_user_role(
`user_id` INT NOT NULL,
`role_id` INT NOT NULL,
PRIMARY KEY (`user_id`,`role_id`),
CONSTRAINT `fk_role_id` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `sys_user`(`id`) ON DELETE CASCADE ON UPDATE CASCADE
)ENGINE =INNODB DEFAULT CHARSET=utf8
ON DELETE CASCADE ON UPDATE CASCADE:代表主表的id发生改变时,从表的id也同时进行delete或update。
- 导入依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
-
在AuthenticationManagerBuilder中,默认提供了一个UserDetailsService接口,此接口中只有一个loadUserByUsername(String username) 方法,由此可知,此方法是可以根据用户名来获取用户信息的,
-
通过实现UserDetailsService接口,从而获取表中用户信息及角色的授权
package com.coffee.springbootstudy.serverimpl;
import com.coffee.springbootstudy.mapper.SysUserMapper;
import com.coffee.springbootstudy.pojo.SysUser;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Resource
SysUserMapper sysUserMapper;
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (username == null) {
throw new RuntimeException("用户名不能为空");
}
//如果用户名不为空,则根据用户名获取用户信息
SysUser sysUser = sysUserMapper.selectByPrimaryKey(username);
if (sysUser == null) {
throw new UsernameNotFoundException("这个用户不存在");
}
/**
1. public User(String username, String password, Collection<? extends GrantedAuthority> authorities) {
2. this(username, password, true, true, true, true, authorities);
3. }
4. 5. userDetails有三个子类,User是其一,User类中包含两个重写方法
*/
List<GrantedAuthority> authorities = new ArrayList<>();
//获取角色
List<String> roleCodeByUserName = sysUserMapper.getRoleCodeByUserName(username);
roleCodeByUserName.forEach(code -> {
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(code);
authorities.add(simpleGrantedAuthority);
System.out.println(code);
});
return new User(sysUser.getUsername(), passwordEncoder().encode(sysUser.getPassword()),authorities);
}
}
- 通过自定义security策略,实现configure(AuthenticationManagerBuilder auth),并且对业务进行调用。
@Resource
UserDetailsService userDetailsService;
//认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
/**
* inMemoryAuthentication在内存中对用户名及密码进行认证
*/
// auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()).withUser("admin").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1", "vip2")
// .and()
// .withUser("zhangsan").password(new BCryptPasswordEncoder().encode("123")).roles("vip2");
/**
* 连接数据库
*/
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
- 测试
我们采用“张三”这个用户进行登录,从表中数据可知他属于普通用户,我们在授权中对普通用户设定了只能访问level2模块下的使用子模块,
注意点:
- 在角色表中,code字段值需要加上“ROLE_”前缀,不然则无法识别。