上一篇博客 sPRingBoot+springSecurity 數據庫動態管理用戶、角色、權限(二) 只是實現了用戶、角色、權限的動態管理,但是其權限管理是有缺陷的,他不支持restful風格的接口權限管理,因為他無法區分客戶端的請求方式。
本片博客是為了彌補此缺陷的,本篇博客將在 springBoot+springSecurity 數據庫動態管理用戶、角色、權限(二) 的基礎上進行修改使其支持 restful 風格的接口的權限管理。
本文目錄: 1. 分析工作量 2. 修改代碼 3. 準備數據 4. 測試
首先分析一下工作量吧,因為要支持 restful 風格的接口,那么我們在判斷用戶是不是有權限訪問的時候不僅要判斷 url 還要判斷 請求方式。 所以我門需要修改數據庫表,因為我門的權限表還沒有method 字段。
由于要判斷 url 和 method 所以要在CustomUserService 類的 loadUserByUsername 方法中要添加 權限的 url 和 method 。但是SimpleGrantedAuthority 只支持傳入一個參數。 所以我門考慮要再寫一個類 實現 GrantedAuthority 接口,并在構造函數中傳入兩個參數。嘻嘻。
由于我們不僅要判斷url 還要 判斷請求方法,所以當然要修改 MyaccessDecisionManager 的decide 方法的內容了。因為:decide 方法是判定是否擁有權限的決策方法 ,三個參數的含義分別為: //authentication 是釋CustomUserService中循環添加到 GrantedAuthority 對象中的權限信息集合. //object 包含客戶端發起的請求的requset信息,可轉換為 HttpServletRequest request = ((FilterInvocation) object).getHttpRequest(); //configAttributes 為MyInvocationSecurityMetadataSource的getAttributes(Object object)這個方法返回的結果,此方法是為了判定用戶請求的url 是否在權限表中,如果在權限表中,則返回給 decide 方法,用來判定用戶是否有此權限。如果不在權限表中則放行。當然在 修改一下 MyInvocationSecurityMetadataSourceService 的getAttributes 方法。//此方法是為了判定用戶請求的url 是否在權限表中,如果在權限表中,則返回給 decide 方法,用來判定用戶是否有此權限。如果不在權限表中則放行。 //因為我不想每一次來了請求,都先要匹配一下權限表中的信息是不是包含此url,我準備直接攔截,不管請求的url 是什么都直接攔截,然后在MyAccessDecisionManager的decide 方法中做 攔截還是放行的決策。5.關閉csrf 6.添加restful 風格的接口
好了分析完了,接下來就是編碼了。
添加method 字段,當然Permission 的java bean 中 也要添加此屬性和其get set方法。

新建java類MyGrantedAuthority 實現 GrantedAuthority 接口
package com.us.example.service;import org.springframework.security.core.GrantedAuthority;/** * Created by yangyibo on 17/2/15. */public class MyGrantedAuthority implements GrantedAuthority { private String url; private String method; public String getPermissionUrl() { return url; } public void setPermissionUrl(String permissionUrl) { this.url = permissionUrl; } public String getMethod() { return method; } public void setMethod(String method) { this.method = method; } public MyGrantedAuthority(String url, String method) { this.url = url; this.method = method; } @Override public String getAuthority() { return this.url + ";" + this.method; }}在CustomUserService 類中使用MyGrantedAuthority
public UserDetails loadUserByUsername(String username) { SysUser user = userDao.findByUserName(username); if (user != null) { List<Permission> permissions = permissionDao.findByAdminUserId(user.getId()); List<GrantedAuthority> grantedAuthorities = new ArrayList<>(); for (Permission permission : permissions) { if (permission != null && permission.getName() != null) { GrantedAuthority grantedAuthority = new MyGrantedAuthority(permission.getUrl(), permission.getMethod()); grantedAuthorities.add(grantedAuthority); } } return new User(user.getUsername(), user.getPassWord(), grantedAuthorities); } else { throw new UsernameNotFoundException("admin: " + username + " do not exist!"); } }關于 什么是csrf 請看我的這篇博客
spring security CSRF 問題
修改 WebSecurityConfig 的configure(HttpSecurity http) 方法 ,添加 .csrf().disable();
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest().authenticated() //任何請求,登錄后可以訪問 .and() .formLogin() .loginPage("/login") .failureUrl("/login?error") .permitAll() //登錄頁面用戶任意訪問 .and() .logout().permitAll(); //注銷行為任意訪問 http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class) .csrf().disable(); }由于我們是要測試restful 風格的權限,所以我門要有restful 的接口
package com.us.example.controller;import com.us.example.domain.Msg;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.ResponseBody;/** * Created by yangyibo on 17/1/18. */@Controllerpublic class HomeController { @RequestMapping("/") public String index(Model model){ Msg msg = new Msg("測試標題","測試內容","歡迎來到HOME頁面,您擁有 ROLE_HOME 權限"); model.addAttribute("msg", msg); return "home"; } @RequestMapping("/admin") @ResponseBody public String hello(){ return "hello admin"; } @RequestMapping("/login") public String login(){ return "login"; } @RequestMapping(value = "/user", method = RequestMethod.GET) @ResponseBody public String getList(){ return "hello getList"; } @RequestMapping(value = "/user", method = RequestMethod.POST) @ResponseBody public String save(){ return "hello save"; } @RequestMapping(value = "/user", method = RequestMethod.PUT) @ResponseBody public String update(){ return "hello update"; }}好了編碼部分完成了
在數據庫中添加測試數據,主要是權限表和權限角色中間表。
結果(角色1 可以訪問 /user 下的所有接口, 角色2 只可以訪問 /user 下的GET請求)權限表: 
權限角色中間表:(此處角色1擁有 權限 6 ,權限6的方法為 ALL 也就是角色6 可以訪問所有路徑為/user 的接口) 
啟動項目,然后在postman 中測試, 1. 登錄admin 后訪問 user 的所有權限,都可以正常訪問。 


put 方法訪問成功 。
登錄abel 后訪問 user 的所有權限,只有GET 權限可以訪問。


put 方法訪問失敗。
半夜碼字。。。 如果本文對您有幫助請給個好評,謝謝。
本文源碼:https://github.com/527515025/springBoot
參考文獻: http://www.cnblogs.com/dongying/p/6106855.html http://www.cnblogs.com/dongying/p/6128268.html
新聞熱點
疑難解答