目录
- 1. 创建springboot项目,引入maven依赖
- 2. application.properties文件对数据库进行配置
- 3.根据RDBC权限模型设计数据库表
- 4. 创建java实体类来映射数据库中的表
- 5. 创建mapper接口对数据库进行操作
- 6.创建MemberDetailsService调用接口完成服务
- 7. 创建工具类MD5Util
- 8. 创建配置类SecurityConfig(这个是spring security的核心)
- 9.创建配置类自定义springboot错误异常处理
- 10.创建controller接口来进行测试
- 11.效果展示
1. 创建springboot项目,引入maven依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<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>
<!--自启动Druid管理后台-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2. application.properties文件对数据库进行配置
spring.datasource.druid.url=jdbc:mysql://127.0.0.1:3306/xxx
spring.datasource.druid.username=xxx
spring.datasource.druid.password=xxx
spring.datasource.druid.initialSize=1
spring.datasource.druid.minIdle=5
spring.datasource.druid.maxActive=10
spring.datasource.druid.maxWait=3000
3.根据RDBC权限模型设计数据库表
RDBC权限模型如下所示:
3.1 创建权限表szp_permission_test
3.2 创建角色权限表szp_role_permission_test
3.3 创建角色表szp_role_test
3.4 创建用户角色表szp_user_role_test
3.5 创建用户表szp_user_test
4. 创建java实体类来映射数据库中的表
4.1 创建PermissionEntity映射权限表
@Data
public class PermissionEntity {
private Integer id;
// 权限名称
private String permName;
// 权限标识
private String permTag;
// 请求url
private String url;
}
4.2 创建RoleEntity映射角色表
@Data
public class RoleEntity {
private Integer id;
private String roleName;
private String roleDesc;
}
4.3 创建UserEntity映射用户表
@Data
public class UserEntity implements UserDetails {
private Integer id;
private String username;
private String realname;
private String password;
private Date createDate;
private Date lastLoginTime;
private boolean enabled;
private boolean accountNonExpired;
private boolean accountNonLocked;
private boolean credentialsNonExpired;
// 用户所有权限,用户表中没有这个字段,为了方便封装了这个属性
private List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
}
5. 创建mapper接口对数据库进行操作
5.1 创建PermissionMapper接口对权限表进行操作
@Mapper
public interface PermissionMapper {
@Select(" select * from szp_permission_test ")
List<PermissionEntity> findAllPermission();
}
5.2 创建UserMapper接口对用户表进行操作
@Mapper
public interface UserMapper {
/**
* 根据用户名称查询
*
* @param userName
* @return
*/
@Select(" select * from szp_user_test where username = #{userName}")
UserEntity findByUsername(@Param("userName") String userName);
/**
* 查询用户的权限根据用户查询权限
*
* @param userName
* @return
*/
@Select(" select permission.* from szp_user_test user" + " inner join szp_user_role_test user_role"
+ " on user.id = user_role.user_id inner join "
+ "szp_role_permission_test role_permission on user_role.role_id = role_permission.role_id "
+ " inner join szp_permission_test permission on role_permission.perm_id = permission.id where user.username = #{userName};")
List<PermissionEntity> findPermissionByUsername(@Param("userName") String userName);
}
6.创建MemberDetailsService调用接口完成服务
@Service
public class MemberDetailsService implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
//登录的时候调用该方法userName查询账户是否存在,验证账户密码
//这时查出来的内容还不包含权限
UserEntity userEntity = userMapper.findByUsername(userName);
if (userEntity == null){
return null;
}
//在根据该账户的userid关联查询角色对应权限,动态进行授权
List<PermissionEntity> permissionList = userMapper.findPermissionByUsername(userName);
//设置权限
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
permissionList.forEach((p -> {
// 意思相同auth.inMemoryAuthentication().withUser("add").password("add").authorities("addMember");
grantedAuthorities.add(new SimpleGrantedAuthority(p.getPermTag()));
}));
userEntity.setAuthorities(grantedAuthorities);
return userEntity;
}
}
7. 创建工具类MD5Util
public class MD5Util {
private static final String SALT = "mayikt";
public static String encode(String password) {
password = password + SALT;
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (Exception e) {
throw new RuntimeException(e);
}
char[] charArray = password.toCharArray();
byte[] byteArray = new byte[charArray.length];
for (int i = 0; i < charArray.length; i++)
byteArray[i] = (byte) charArray[i];
byte[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
public static void main(String[] args) {
System.out.println(MD5Util.encode("mayikt_add"));
}
}
8. 创建配置类SecurityConfig(这个是spring security的核心)
@Component
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private PermissionMapper permissionMapper;
@Autowired
private MemberDetailsService memberDetailsService;
/**
* 新增security授权的账户
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//这种方法写死
// auth.inMemoryAuthentication().withUser("admin").password("admin")
// .authorities("addMember","delMember","updateMember","showMember");
//
// //这个账号只能访问addMember
// auth.inMemoryAuthentication().withUser("add").password("add").authorities("addMember");
//这种方法是动态的
auth.userDetailsService(memberDetailsService).passwordEncoder(new PasswordEncoder() {//设置password编码
@Override
public String encode(CharSequence rawPassword) {
return MD5Util.encode((String) rawPassword);
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
String rawPass = MD5Util.encode((String) rawPassword);
boolean result = rawPass.equals(encodedPassword);
return result;
}
});
}
@Override
protected void configure(HttpSecurity http) throws Exception {
/**
* 下面是写死的方法,不好
*/
//配置认证方式token/form表单(这个不咋用),设置为httpBasic模式
// http.authorizeRequests() //拿到请求
// .antMatchers("/**") //匹配拦截所有请求
// .fullyAuthenticated()
// .and()
// .httpBasic(); //basic请求,会弹出提示框输入账号密码
// http.authorizeRequests() //拿到请求
// .antMatchers("/**") //匹配拦截所有请求
// .fullyAuthenticated()
// .and()
// .formLogin(); //form表单请求
// // /addMember接口的权限名称为addMember
// http.authorizeRequests()
// .antMatchers("/addMember").hasAnyAuthority("addMember")
// .antMatchers("/delMember").hasAnyAuthority("delMember")
// .antMatchers("/updateMember").hasAnyAuthority("updateMember")
// .antMatchers("/showMember").hasAnyAuthority("showMember")
// //可以允许login不被拦截
// .antMatchers("/login").permitAll()
// //设置自定义登录页面
// .antMatchers("/**").fullyAuthenticated()
// .and().formLogin();
.loginPage("/login").and().csrf().disable(); //权限不够就跳转到/login,不知道为啥加了之后不行
/**
* 连接数据库动态查找权限
*/
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequests = http.authorizeRequests();
//需要查询到所有的权限
List<PermissionEntity> allPermission = permissionMapper.findAllPermission();
allPermission.forEach((p->{
//添加规则
authorizeRequests.antMatchers(p.getUrl()).hasAnyAuthority(p.getPermTag());
}));
//可以允许login不被拦截
authorizeRequests.antMatchers("/login").permitAll()
//设置自定义登录页面
.antMatchers("/**").fullyAuthenticated()
.and().formLogin();
}
}
9.创建配置类自定义springboot错误异常处理
/**
* 自定义SpringBoot 错误异常
*/
@Configuration
public class WebServerAutoConfiguration {
@Bean
public ConfigurableServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
ErrorPage errorPage400 = new ErrorPage(HttpStatus.BAD_REQUEST, "/error/400");
ErrorPage errorPage401 = new ErrorPage(HttpStatus.UNAUTHORIZED, "/error/401");
ErrorPage errorPage403 = new ErrorPage(HttpStatus.FORBIDDEN, "/error/403");
ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND, "/error/404");
ErrorPage errorPage415 = new ErrorPage(HttpStatus.UNSUPPORTED_MEDIA_TYPE, "/error/415");
ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500");
factory.addErrorPages(errorPage400, errorPage401, errorPage403, errorPage404, errorPage415, errorPage500);
return factory;
}
}
10.创建controller接口来进行测试
@RestController
public class MemberController {
/**
* 增加用户
*
* @return
*/
@RequestMapping("/addMember")
public String addMember() {
return "addMember";
}
/**
* 删除用户
*
* @return
*/
@RequestMapping("/delMember")
public String delMember() {
return "delMember";
}
/**
* updateMember
*
* @return
*/
@RequestMapping("/updateMember")
public String updateMember() {
return "updateMember";
}
/**
* showMember
*
* @return
*/
@RequestMapping("/showMember")
public String showMember() {
return "showMember";
}
/**
* There is no PasswordEncoder mapped for the id "null"
* 原因:升级为Security5.0以上密码支持多中加密方式,恢复以前模式
* @return
*/
@Bean
public static NoOpPasswordEncoder passwordEncoder() {
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}
}
11.效果展示
输入http://localhost:8080/addMember,会自动跳转到http://localhost:8080/login
这里输入mayikt_add用户,对应有addMember的权限
登录后显示已进入addMember
修改url为http://localhost:8080/delMember
发现无法进入,显示权限不足