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 全真劍法不可以訪問

發佈了241 篇原創文章 · 獲贊 87 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章