SpringSecurity---细粒度的权限控制

第五章 细粒度权限控制

5.1 前置细节【Role和Authority的区别】

5.1.1 用户拥有的权限表示

  1. roles("ADMIN","学徒","宗师")
  1. authorities("USER","MANAGER");

5.1.2 给资源授予权限(角色或权限)

//.antMatchers("/level1/**").hasRole("学徒")

//.antMatchers("/level1/**").hasAnyRole("学徒","ADMIN")//拥有任何一个角色都可以访问

.antMatchers("/level1/**").hasAnyAuthority("学徒","ADMIN") //拥有任何一个权限都可以访问

.antMatchers("/level2/**").hasRole("大师")

.antMatchers("/level3/**").hasRole("宗师")

5.1.3 权限:【roles和authorities区别】

  1. roles("ADMIN","学徒","宗师")

增加"ROLE_"前缀存放:【"ROLE_ADMIN","ROLE_学徒","ROLE_宗师"】

表示拥有的权限。一个角色表示的是多个权限

用户传入的角色不能以ROLE_开头,否则会报错。ROLE_是自动加上的

如果我们保存的用户的角色:直接传入角色的名字,权限【new SimpleGrantedAuthority("ROLE_" + role)】保存即可

  1. authorities("USER","MANAGER");

原样存放:【"USER","MANAGER"】

表示拥有的权限。

如果我们保存的是真正的权限;直接传入权限名字,权限【new SimpleGrantedAuthority(role)】保存

无论是Role还是Authority都保存在  List<GrantedAuthority>,每个用户都拥有自己的权限集合->List<GrantedAuthority>

5.1.4 验证用户权限

  1. 通过角色(权限)验证:

.antMatchers("/level1/**").hasRole("学徒")

.antMatchers("/level1/**").hasAnyRole("学徒","ADMIN")

拥有任何一个角色都可以访问

验证时会自动增加"ROLE_"进行查找验证:【"ROLE_学徒","ROLE_ADMIN"】

通过权限验证

.antMatchers("/level1/**").hasAuthority("学徒")

.antMatchers("/level1/**").hasAnyAuthority("学徒","ADMIN")

拥有任何一个权限都可以访问

验证时原样查找进行验证:【"学徒","ADMIN"】

5.2 细粒度的资源控制

  1. authenticated():通过认证的用户都可以访问
  2. permitAll():允许所有人访问,即使未登录
  3. authorizeRequests():更细粒度的控制
  4. access(String): //SpEL:Spring表达式

.access("hasRole('大师') AND hasAuthority('user:delete') OR hasIpAddress('192.168.50.15')")

5.3 细粒度的资源控制相应注解

使用注解与SpEl进行细粒度权限控制

5.3.1 开启注解控制权限模式

@EnableWebSecurity:开启 Spring Security 注解

@EnableGlobalMethodSecurity(prePostEnabled=true):开启全局的细粒度方法级别权限控制功能

5.3.2 几个权限检查注解

1 @PreAuthorize:方法执行前检查

@PreAuthorize("hasRole('ADMIN')") 

public void addUser(User user){ 

    //如果具有ROLE_ADMIN 权限 则访问该方法 

    .... 

}

2 @PostAuthorize:方法执行后检查,失败抛异常

@PostAuthorize:允许方法调用,但是,如果表达式结果为false抛出异常 

//returnObject可以获取返回对象user,判断user属性username是否和访问该方法的用户对象的用户名一样。不一样则抛出异常。 

@PostAuthorize("returnObject.user.username==principal.username") 

public User getUser(int userId){ 

   //允许进入

... 

    return user;

}

3 @PostFilter:允许方法调用,但是按照表达式过滤方法结果

 //将结果过滤,即选出性别为男的用户 

@PostFilter("returnObject.user.sex=='' ") 

public List<User> getUserList(){ 

    //允许进入

    ... 

    return user;

}

4 @PreFilter:允许方法调用,但必须在进入方法前过滤输入值

5 @Secured:拥有指定角色才可以访问方法

@Secured('ADMIN')   等价于    @PreAuthorize("hasRole('ADMIN')")

5.4 细粒度的资源控制注解中可写的表达式

https://docs.spring.io/spring-security/site/docs/4.0.1.RELEASE/reference/htmlsingle/#el-common-built-in

所有能使用的表达式见上面文档连接

5.5 细粒度权限控制实现步骤 ★

5.5.1 开启全局的细粒度方法级别权限控制功能

@EnableGlobalMethodSecurity(prePostEnabled = true)

@EnableWebSecurity

@Configuration

public class AppSecurityConfig extends WebSecurityConfigurerAdapter {

}

5.5.2 将手动授权的方式注释掉

//.antMatchers("/level1/**").hasRole("学徒")

//.antMatchers("/level1/**").hasAnyRole("学徒","ADMIN")

//.antMatchers("/level1/**").hasAnyAuthority("学徒","ADMIN")

//.antMatchers("/level1/**").hasAuthority("学徒")

//.antMatchers("/level2/**").hasRole("大师")

//.antMatchers("/level3/**").hasRole("宗师")        

5.5.3 给访问资源的方法增加注解,进行访问授权

@Controller

public class GongfuController { 

/**

   * 授权(权限检查)使用AOP;MethodSecurityInterceptor

   *                 方法执行之前AccessDecisionManager利用投票机制决定这个方法是否可运行

 *

   */

@PreAuthorize("hasRole('学徒') AND hasAuthority('luohan')")

@GetMapping("/level1/1")

public String leve1Page(){

return "/level1/1";

}

@PreAuthorize("hasRole('学徒') AND hasAuthority('wudang')")

@GetMapping("/level1/2")

public String leve1Page2(){

return "/level1/2";

}

@PreAuthorize("hasRole('学徒') AND hasAuthority('quanzhen')")

@GetMapping("/level1/3")

public String leve1Page3(){

return "/level1/3";

}

}

5.5.4 通过数据库加载用户权限

@Service

public class AppUserDetailsServiceImpl implements UserDetailsService {

 

@Autowired

JdbcTemplate jdbcTemplate ;

 

@Override

public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

String sql = "select  * from t_admin where loginacct=?";

Map<String, Object> map = jdbcTemplate.queryForMap(sql, username);

 

//查询用户拥有的角色集合

String sql1="SELECT t_role.* FROM t_role LEFT JOIN t_admin_role ON t_admin_role.roleid=t_role.id WHERE t_admin_role.adminid=?";                

List<Map<String, Object>> roleList = jdbcTemplate.query(sql1, new ColumnMapRowMapper(), map.get("id"));

 

//查询用户拥有的权限集合

String sql2 = "SELECT distinct t_permission.* FROM t_permission LEFT JOIN t_role_permission ON t_role_permission.permissionid = t_permission.id LEFT JOIN t_admin_role ON t_admin_role.roleid=t_role_permission.roleid WHERE t_admin_role.adminid=?";

List<Map<String, Object>> permissionList = jdbcTemplate.query(sql2, new ColumnMapRowMapper(), map.get("id"));

 

//用户权限=【角色+权限】

Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();

 

for (Map<String, Object> rolemap : roleList) {

String rolename = rolemap.get("name").toString();

authorities.add(new SimpleGrantedAuthority("ROLE_"+rolename));

}

for (Map<String, Object> permissionmap : permissionList) {

String permissionName = permissionmap.get("name").toString();

if(!StringUtils.isEmpty(permissionName)) {

authorities.add(new SimpleGrantedAuthority(permissionName));

}

}

 

//return new User(map.get("loginacct").toString(),map.get("userpswd").toString(),

//AuthorityUtils.createAuthorityList("ADMIN","USER"));

return new User(map.get("loginacct").toString(),map.get("userpswd").toString(),authorities);

}

}

5.5.5 准备数据

查询用户拥有的角色集合

查询用户拥有的权限集合

SELECT

  t_role.*

FROM

  t_role

  LEFT JOIN t_admin_role

    ON t_admin_role.roleid = t_role.id

WHERE t_admin_role.userid = 1

SELECT DISTINCT

  t_permission.*

FROM

  t_permission

  LEFT JOIN t_role_permission

    ON t_role_permission.permissionid = t_permission.id

  LEFT JOIN t_admin_role

    ON t_admin_role.roleid = t_role_permission.roleid

WHERE t_admin_role.userid = 1

5.5.6 测试结果

登录认证通过,可以登录到成功页面

访问【学徒】角色下的资源:

/level1/1 罗汉拳不可以访问

/level1/2 武当长拳可以访问

/level1/3 全真剑法不可以访问

发布了227 篇原创文章 · 获赞 77 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/m2606707610/article/details/104099440
今日推荐