更新时间:2022-08-13 10:29:19
目录
目录创建于2017-12-18
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private ReaderRepository readerRepository;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").access("hasRole('READER')")//要求登陆者进入根目录必须具有 READER 的角色
.antMatchers("/**").permitAll()//其他页面开放了权限
.and()
.formLogin()
.loginPage("/login")//登录表单的路径
.failureUrl("/login?error=true");
}
@Override
protected void configure(
AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(new UserDetailsService() {//定义自定义的UserDetailService
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
UserDetails userDetails = readerRepository.findOne(username);
if (userDetails != null) {
return userDetails;
}
throw new UsernameNotFoundException("User '" + username + "' not found.");
}
});
}
}
Repository类
public interface ReaderRepository extends JpaRepository<Reader, String> {}
//登录实体类
@Entity
public class Reader implements UserDetails {
private static final long serialVersionUID = 1L;
@Id
private String username;
private String fullname;
private String password;
//省略setget
//授予READER权限
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority("ROLE_READER"));
}
//不过期
@Override
public boolean isAccountNonExpired() { return true;}
//不加锁
@Override
public boolean isAccountNonLocked() {return true;}
//不禁用
@Override
public boolean isCredentialsNonExpired() {return true;}
//可用
@Override
public boolean isEnabled() { return true;}
}
在页面上加上角色的判断来控制数据显示,业务操作等功能
根据书上案例代码,可以得出结论,用户表,角色表,用户角色关联表,用户表是可以多张的,角色公用一张即可,然后关联表也对应的多张,就能实现具体的业务需求
Author
Admin
Reader
三个类 继承了UserDetails接口的实体类的配置
//配置多对多的关系,用户和角色(权限)之间的关系,是通用的改下属性名即可
@ManyToMany(cascade = {CascadeType.REFRESH},fetch = FetchType.EAGER)
private List<AllRoles> roles ;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
List<AllRoles> roles = this.getRoles();
for(AllRoles role:roles){
auths.add(new SimpleGrantedAuthority(role.getRole_name()));
}
return auths;
}
// 登录的用户名,如果属性不是叫username,就要重写,返回应该的用户名属性就是了
@Override
public String getUsername() { return this.reader_name;}
@Override
public boolean isAccountNonExpired() {return true;}
@Override
public boolean isAccountNonLocked() {return true;}
@Override
public boolean isCredentialsNonExpired() {return true;}
@Override
public boolean isEnabled() {return true;}
spirng.jpa.hibernate.ddl-auto=update
特殊字符
把类型放进去,然后正则取出来角色表(序列id,用户编码,角色)
这样的话扩展就只要加表,使用同一个主键生成策略就可以了
思考:
需要先配置这个配置类,后面的注解才会生效
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration{}
@PreAuthorize
方法调用前,基于表达式的计算结果来限制方法的访问@PostAuthorize
允许方法调用,如果表达式是false 抛出安全异常@PostFilter
允许方法调用,按照表达式来过滤方法的结果@PreFilter
允许方法调用,必须进入方法前过滤输入值
方法调用前验证权限,示例:
@PreAuthorize("hasRole('ROLE_ADMIN')")
只允许该权限的用户访问@PreAuthorize("(hasRole('ROLE_READER') and #user.text.length()<=140 ) or hasRole('ROLE_AUTHOR')")
@PostAuthorize("returnObject.spitter.username == principal.username")
以上是保护方法的调用,但是有时候保护的是数据的输入输出:
@PreAuthorize("hasAnyRole({'ROLE_ADMIN','ROLE_USER'})")
@PostFilter("hasRole('ROLE_ADMIN') || filterObject.user.username == principal.name")
public List<User> getUsers(){}
@PreAuthorize("hasAnyRole({'ROLE_ADMIN','ROLE_USER'})")
@PreFilter("hasRole('ROLE_ADMIN') || targetObject.user.username == principal.name")
public void deleteUsers(){List<User> users}
@PreFilter("hasPermission(targetObject,'delete')")
用户是否有权限删除目标对象?DefaultMethodSecurityExperssionHandler ex = new De...();
ex.setPermissionEvaluator(new 自定义类);
return ex;