<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ## 綜合實例 ![](https://box.kancloud.cn/50d7379f373dcb31ce103ede7d10b334_458x249.png) ## 簡單數據字典 用戶 (sys\_user) | 名稱 | 類型 | 長度 | 描述 | | --- | --- | --- | --- | | id | bigint | | 編號 主鍵 | | username | varchar | 100 | 用戶名 | | password | varchar | 100 | 密碼 | | salt | varchar | 50 | 鹽 | | role_ids | varchar | 100 | 角色列表 | | locked | bool | | 賬戶是否鎖定 | 組織機構 (sys\_organization) | 名稱 | 類型 | 長度 | 描述 | | --- | --- | --- | --- | | id | bigint | | 編號 主鍵 | | name | varchar | 100 | 組織機構名 | | priority | int | 100 | 顯示順序 | | parent_id | bigint | 50 | 父編號 | | parent_ids | varchar | 100 | 父編號列表 | | available | bool | | 是否可用 | 資源 (sys\_resource) | 名稱 | 類型 | 長度 | 描述 | | --- | --- | --- | --- | | id | bigint | | 編號 主鍵 | | name | varchar | 100 | 資源名稱 | | type | varchar | 50 | 資源類型 | | priority | int | 100 | 顯示順序 | | parent_id | bigint | 50 | 父編號 | | parent_ids | varchar | 100 | 父編號列表 | | permission | varchar | 100 | 權限字符串 | | available | bool | | 是否可用 | 角色 (sys\_role) | 名稱 | 類型 | 長度 | 描述 | | --- | --- | --- | --- | | id | bigint | | 編號 主鍵 | | role | varchar | 100 | 角色名稱 | | description | varchar | 100 | 角色描述 | | resource_ids | varchar | 100 | 授權的資源 | | available | bool | | 是否可用 | **資源**:表示菜單元素、頁面按鈕元素等;菜單元素用來顯示界面菜單的,頁面按鈕是每個頁面可進行的操作,如新增、修改、刪除按鈕;使用 type 來區分元素類型(如 menu 表示菜單,button 代表按鈕),priority 是元素的排序,如菜單顯示順序;permission 表示權限;如用戶菜單使用 `user:*`;也就是把菜單授權給用戶后,用戶就擁有了 `user:*` 權限;如用戶新增按鈕使用 user:create,也就是把用戶新增按鈕授權給用戶后,用戶就擁有了 user:create 權限了;available 表示資源是否可用,如菜單顯示 / 不顯示。 **角色**:role 表示角色標識符,如 admin,用于后臺判斷使用;description 表示角色描述,如超級管理員,用于前端顯示給用戶使用;resource\_ids 表示該角色擁有的資源列表,即該角色擁有的權限列表(顯示角色),即角色是權限字符串集合;available 表示角色是否可用。 **組織機構**:name 表示組織機構名稱,priority 是組織機構的排序,即顯示順序;available 表示組織機構是否可用。 **用戶**:username 表示用戶名;password 表示密碼;salt 表示加密密碼的鹽;role\_ids 表示用戶擁有的角色列表,可以通過角色再獲取其權限字符串列表;locked 表示用戶是否鎖定。 此處如資源、組織機構都是樹型結構: | id | name | parent_id | parent_ids | | --- | --- | --- | --- | | 1 | 總公司 | 0 | 0/ | | 2 | 山東分公司 | 1 | 0/1/ | | 3 | 河北分公司 | 1 | 0/1/ | | 4 | 濟南分公司 | 2 | 0/1/2/ | parent\_id 表示父編號,parent\_ids 表示所有祖先編號;如 0/1/2/ 表示其祖先是 2、1、0;其中根節點父編號為 0。 為了簡單性,如用戶 - 角色,角色 - 資源關系直接在實體(用戶表中的 role\_ids,角色表中的 resource\_ids)里完成的,沒有建立多余的關系表,如要查詢擁有 admin 角色的用戶時,建議建立關聯表,否則就沒必要建立了。在存儲關系時如 role\_ids=1,2,3,;多個之間使用逗號分隔。 用戶組、組織機構組本實例沒有實現,即可以把一組權限授權給這些組,組中的用戶 / 組織機構就自動擁有這些角色 / 權限了;另外對于用戶組可以實現一個默認用戶組,如論壇,不管匿名 / 登錄用戶都有查看帖子的權限。 更復雜的權限請參考我的《JavaEE 項目開發腳手架》:[](http://github.com/zhangkaitao/es)<http://github.com/zhangkaitao/es>。 ## 表 / 數據 SQL 具體請參考 * sql/ shiro-schema.sql (表結構) * sql/ shiro-data.sql (初始數據) 默認用戶名 / 密碼是 admin/123456。 ## 實體 具體請參考 com.github.zhangkaitao.shiro.chapter16.entity 包下的實體,此處就不列舉了。 ## DAO 具體請參考 com.github.zhangkaitao.shiro.chapter16.dao 包下的 DAO 接口及實現。 ## Service 具體請參考 com.github.zhangkaitao.shiro.chapter16.service 包下的 Service 接口及實現。以下是出了基本 CRUD 之外的關鍵接口: ``` java public interface ResourceService { Set<String> findPermissions(Set<Long> resourceIds); //得到資源對應的權限字符串 List<Resource> findMenus(Set<String> permissions); //根據用戶權限得到菜單 } ``` ``` java public interface RoleService { Set<String> findRoles(Long... roleIds); //根據角色編號得到角色標識符列表 Set<String> findPermissions(Long[] roleIds); //根據角色編號得到權限字符串列表 } ``` ``` java public interface UserService { public void changePassword(Long userId, String newPassword); //修改密碼 public User findByUsername(String username); //根據用戶名查找用戶 public Set<String> findRoles(String username);// 根據用戶名查找其角色 public Set<String> findPermissions(String username);// 根據用戶名查找其權限 } ``` Service 實現請參考源代碼,此處就不列舉了。 ## UserRealm 實現 ``` java public class UserRealm extends AuthorizingRealm { @Autowired private UserService userService; protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = (String)principals.getPrimaryPrincipal(); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); authorizationInfo.setRoles(userService.findRoles(username)); authorizationInfo.setStringPermissions(userService.findPermissions(username)); System.out.println(userService.findPermissions(username)); return authorizationInfo; } protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = (String)token.getPrincipal(); User user = userService.findByUsername(username); if(user == null) { throw new UnknownAccountException();//沒找到帳號 } if(Boolean.TRUE.equals(user.getLocked())) { throw new LockedAccountException(); //帳號鎖定 } return new SimpleAuthenticationInfo( user.getUsername(), //用戶名 user.getPassword(), //密碼 ByteSource.Util.bytes(user.getCredentialsSalt()),//salt=username+salt getName() //realm name ); } } ``` 此處的 UserRealm 和《第六章 Realm 及相關對象》中的 UserRealm 類似,通過 UserService 獲取帳號及角色 / 權限信息。 ## Web 層控制器 ``` java @Controller public class IndexController { @Autowired private ResourceService resourceService; @Autowired private UserService userService; @RequestMapping("/") public String index(@CurrentUser User loginUser, Model model) { Set<String> permissions = userService.findPermissions(loginUser.getUsername()); List<Resource> menus = resourceService.findMenus(permissions); model.addAttribute("menus", menus); return "index"; } } ``` IndexController 中查詢菜單在前臺界面顯示,請參考相應的 jsp 頁面; ``` java @Controller public class LoginController { @RequestMapping(value = "/login") public String showLoginForm(HttpServletRequest req, Model model) { String exceptionClassName = (String)req.getAttribute("shiroLoginFailure"); String error = null; if(UnknownAccountException.class.getName().equals(exceptionClassName)) { error = "用戶名/密碼錯誤"; } else if(IncorrectCredentialsException.class.getName().equals(exceptionClassName)) { error = "用戶名/密碼錯誤"; } else if(exceptionClassName != null) { error = "其他錯誤:" + exceptionClassName; } model.addAttribute("error", error); return "login"; } } ``` LoginController 用于顯示登錄表單頁面,其中 shiro authc 攔截器進行登錄,登錄失敗的話會把錯誤存到 shiroLoginFailure 屬性中,在該控制器中獲取后來顯示相應的錯誤信息。 ``` java @RequiresPermissions("resource:view") @RequestMapping(method = RequestMethod.GET) public String list(Model model) { model.addAttribute("resourceList", resourceService.findAll()); return "resource/list"; } ``` 在控制器方法上使用 @RequiresPermissions 指定需要的權限信息,其他的都是類似的,請參考源碼。 ## Web 層標簽庫 com.github.zhangkaitao.shiro.chapter16.web.taglib.Functions 提供了函數標簽實現,有根據編號顯示資源 / 角色 / 組織機構名稱,其定義放在 src/main/webapp/tld/zhang-functions.tld。 ## Web 層異常處理器 ``` java @ControllerAdvice public class DefaultExceptionHandler { @ExceptionHandler({UnauthorizedException.class}) @ResponseStatus(HttpStatus.UNAUTHORIZED) public ModelAndView processUnauthenticatedException(NativeWebRequest request, UnauthorizedException e) { ModelAndView mv = new ModelAndView(); mv.addObject("exception", e); mv.setViewName("unauthorized"); return mv; } } ``` 如果拋出 UnauthorizedException,將被該異常處理器截獲來顯示沒有權限信息。 ## Spring 配置——spring-config.xml 定義了 context:component-scan 來掃描除 web 層的組件、dataSource(數據源)、事務管理器及事務切面等;具體請參考配置源碼。 ## Spring 配置——spring-config-cache.xml 定義了 spring 通用 cache,使用 ehcache 實現;具體請參考配置源碼。 ## Spring 配置——spring-config-shiro.xml 定義了 shiro 相關組件。 ``` xml <bean id="userRealm" class="com.github.zhangkaitao.shiro.chapter16.realm.UserRealm"> <property name="credentialsMatcher" ref="credentialsMatcher"/> <property name="cachingEnabled" value="false"/> </bean> ``` userRealm 組件禁用掉了 cache,可以參考 [](https://github.com/zhangkaitao/es/tree/master/web/src/main/java/com/sishuok/es/extra/aop)<https://github.com/zhangkaitao/es/tree/master/web/src/main/java/com/sishuok/es/extra/aop> 實現自己的 cache 切面;否則需要在修改如資源 / 角色等信息時清理掉緩存。 ``` xml <bean id="sysUserFilter" class="com.github.zhangkaitao.shiro.chapter16.web.shiro.filter.SysUserFilter"/> ``` sysUserFilter 用于根據當前登錄用戶身份獲取 User 信息放入 request;然后就可以通過 request 獲取 User。 ``` xml <property name="filterChainDefinitions"> <value> /login = authc /logout = logout /authenticated = authc /** = user,sysUser </value> </property> ``` 如上是 shiroFilter 的 filterChainDefinitions 定義。 ## Spring MVC 配置——spring-mvc.xml 定義了 spring mvc 相關組件。 ``` xml <mvc:annotation-driven> <mvc:argument-resolvers> <bean class="com.github.zhangkaitao.shiro.chapter16 .web.bind.method.CurrentUserMethodArgumentResolver"/> </mvc:argument-resolvers> </mvc:annotation-driven> ``` 此處注冊了一個 @CurrentUser 參數解析器。如之前的 IndexController,從 request 獲取 shiro sysUser 攔截器放入的當前登錄 User 對象。 ## Spring MVC 配置——spring-mvc-shiro.xml 定義了 spring mvc 相關組件。 ``` xml <aop:config proxy-target-class="true"></aop:config> <bean class="org.apache.shiro.spring.security .interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean> ``` 定義 aop 切面,用于代理如 @RequiresPermissions 注解的控制器,進行權限控制。 ## web.xml 配置文件 定義 Spring ROOT 上下文加載器、ShiroFilter、及 SpringMVC 攔截器。具體請參考源碼。 ## JSP 頁面 ``` xml <shiro:hasPermission name="user:create"> <a href="${pageContext.request.contextPath}/user/create">用戶新增</a><br/> </shiro:hasPermission> ``` 使用 shiro 標簽進行權限控制。具體請參考源碼。 ## 系統截圖 訪問 [](http://localhost:8080/chapter16/)<http://localhost:8080/chapter16/>; 首先進入登錄頁面,輸入用戶名 / 密碼(默認 admin/123456)登錄: ![](https://box.kancloud.cn/055e0b516ba0972ada28f6ec874b4c3d_299x107.png) 登錄成功后到達整個頁面主頁,并根據當前用戶權限顯示相應的菜單,此處菜單比較簡單,沒有樹型結構顯示 ![](https://box.kancloud.cn/58e0ba8dcb703126d951a76cc13ec85f_730x208.png) 然后就可以進行一些操作,如組織機構維護、用戶修改、資源維護、角色授權 ![](https://box.kancloud.cn/e937d04fcc485ec35bce488017b39c99_615x143.png) ![](https://box.kancloud.cn/51a7fbfe955989fe532b3835520ea739_429x208.png) ![](https://box.kancloud.cn/5d97caa6e0ea3c6fc528a5fa7bd52de6_957x322.png) ![](https://box.kancloud.cn/60b38aec906bce5d41280db5f1d15455_381x274.png) ## 相關資料 《跟我學 spring3》 [](http://www.iteye.com/blogs/subjects/spring3)<http://www.iteye.com/blogs/subjects/spring3> 《跟開濤學 SpringMVC》 [](http://www.iteye.com/blogs/subjects/kaitao-springmvc)<http://www.iteye.com/blogs/subjects/kaitao-springmvc> 《簡單 shiro 擴展實現 NOT、AND、OR 權限驗證》 [](http://jinnianshilongnian.iteye.com/blog/1864800)<http://jinnianshilongnian.iteye.com/blog/1864800> 《Shiro+Struts2+Spring3 加上 @RequiresPermissions 后 @Autowired 失效》 [](http://jinnianshilongnian.iteye.com/blog/1850425)<http://jinnianshilongnian.iteye.com/blog/1850425> 更復雜的權限請參考我的《JavaEE 項目開發腳手架》:[](http://github.com/zhangkaitao/es)<http://github.com/zhangkaitao/es>,提供了更加復雜的實現。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看