<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>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                http://blog.csdn.net/shuaicihai/article/details/58391481 ## 權限控制的方式 從類別上分,有兩大類:? - 認證:你是誰?–識別用戶身份。? - 授權:你能做什么?–限制用戶使用的功能。 ## 權限的控制級別 從控制級別(模型)上分:? - URL級別-粗粒度? - 方法級別-細粒度? - 頁面級別-自定義標簽(顯示)? - 數據級別-最細化的(數據) ### URL級別的權限控制-粗粒度 在web.xml中配置一個過濾器filter,在過濾器中,對請求的地址進行解析,字符串截取:? url.substring()…把上下文前面的路徑都截取掉,剩下user_login.action。? 過濾器代碼:? 以通過查詢數據庫,來判斷,當前登錄用戶,是否可以訪問user_login.action。? url級別控制,每次請求過程中只控制一次 ,相比方法級別權限控制 是粗粒度的 !URL級別權限控制,基于Filter實現。 ### 方法級別的權限控制-細粒度 aop面向切面的編程,在方法執行之前,進行權限判斷,如果沒有權限,拋出異常,終止方法的繼續運行。? 自定義注解 在需要權限控制方法上, 添加需要的權限信息? 代理 (Spring AOP ),在目標方法運行時 進行增強 ,通過反射技術獲取目標方法上注解中權限 , 查詢數據庫獲取當前登陸用戶具有權限,進行比較。? 相比URL級別權限控制, 可以控制到服務器端執行的每個方法,一次請求中可以控制多次。 ### 頁面(顯示)級別的權限控制-自定義標簽 頁面顯示的權限控制,通常是通過 自定義標簽來實現 ### 數據級別的權限控制 在每條數據上增加一個字段,該字段記錄了權限的值。數據和權限綁定。? 代碼,你在查詢數據的時候,需要去權限和用戶對應表中,通過當前登錄用戶的條件,查詢出你的數據權限。然后再將數據權限作為一個條件,放到業務表中進行查詢。從而限制了數據的訪問。 ## 權限系統的數據表設計 * 資源:用戶要訪問的目標,通常是服務中的程序或文件 * 權限:用戶具有訪問某資源的能力 * 角色:權限的集合,為了方便給用戶授權。 * 用戶:訪問系統的’人’。 表對象實體:? - 用戶(User)表:訪問系統的用戶,比如用戶登錄要用? - 權限(Function)表:系統某個功能允許訪問而對應的權限? - 角色(Role)表:角色是權限的集合(權限組),方便用戶授權。 表對象之間的關系:? - 用戶和角色關系表:一個用戶對應N個角色,一個角色可以授予N個用戶—》多對多關系? - 角色和權限關系表:一個角色包含N個權限,一個權限可以屬于N個角色—》多對多關系 完整的權限相關表:? URL級別權限控制包含:資源表、權限表、角色表、用戶表,以及相關關系(都是多對多),共7張表。? 方法級別的權限控制包含:功能權限、角色、用戶,以及相關關系(都是多對多),共5張表。 但Apache Shiro框架支持的URL級別權限控制,是將資源和資源權限對應關系配置到了配置文件中,不需要表的支撐,只需要5張表了。 ## Apache Shiro權限控制 Apache Shiro 可以不依賴任何技術使用, 可以直接和web整合,通常在企業中和Spring 結合使用。 Authentication: 認證 — 用戶登錄? Authorization : 授權 —- 功能權限管理 ### 通過引入Maven坐標導入shiro 官方建議:不推薦直接引入shiro-all,依賴比較多,原因怕有jar沖突。官方推薦根據需要單獨導入jar。 ### Shiro基本原理 Shiro的框架的體系結構:? ![](http://i.imgur.com/DAWUzJr.png) Shiro權限控制流程的原理:? ![](http://i.imgur.com/7yeDKCt.png) * 應用代碼 —- 調用Subject (shiro的Subject 就代表當前登陸用戶) 控制權限 —- Subject 在shiro框架內部 調用 Shiro SecurityManager 安全管理器 —– 安全管理器調用 Realm (程序和安全數據連接器 )。 * Subject要進行任何操作,都必須要調用安全管理器(對我們來說是自動的)。? 而安全管理器會調用指定的Realms對象,來連接安全數據。 * Realms用來編寫安全代碼邏輯和訪問安全數據,是連接程序和安全數據的橋梁。 ## URL級別的權限控制 ### 配置整合和url級別認證 配置過濾器web.xml:放在struts的前端控制器之前配置,但放在openEntitymanage之后。 ~~~ <!-- shiro權限過濾器 --> <filter> <!-- 這里的 filter-name 要和 spring 的 applicationContext-shiro.xml 里的 org.apache.shiro.spring.web.ShiroFilterFactoryBean 的 bean name 相同 --> <filter-name>shiroSecurityFilter</filter-name> <!-- spring的代理過濾器類:以前的過濾器 --> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <!-- 該值缺省為false,表示生命周期由SpringApplicationContext管理,設置為true則表示由ServletContainer管理 --> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>shiroSecurityFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 配置ApplicationContext.xml:(shiro權限控制過濾器+ shiro安全管理器) <!-- shiro權限控制過濾器bean --> <bean id="shiroSecurityFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- shiro 的核心安全接口 --> <property name="securityManager" ref="securityManager" /> <!-- 要求登錄時的鏈接 --> <property name="loginUrl" value="/login.jsp" /> <!-- 登陸成功后要跳轉的連接 --> <property name="successUrl" value="/index.jsp" /> <!-- 未授權時要跳轉的連接,權限不足的跳轉路徑 --> <property name="unauthorizedUrl" value="/unauthorized.jsp" /> <!-- shiro 連接約束配置(URL級別的權限控制),即URL和filter的關系,URL控制規則:路徑=規則名 --> <property name="filterChainDefinitions"> <value> <!--按需求配置--> /login.jsp = anon /validatecode.jsp = anon /js/** = anon /css/** = anon /images/** = anon /user_login.action* = anon /page_base_staff.action = anon /page_base_region.action = perms["user"] /page_base_subarea.action = roles["operator"] /** = authc </value> </property> </bean> <!-- shiro安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <!-- 注入 Realm連接安全數據--> </bean> ~~~ 配置shiroFilter 其實是一個過濾器鏈,含有10個Filter(校驗功能)。 ![](http://i.imgur.com/zKgRBea.png) 常用:? 認證? - anon不用認證(登錄)就能訪問(單詞注意大小寫)? - authc: 需要認證(登錄)才能使用,例如/admins/user/**=authc,沒有參數。? 授權:? - perms:需要擁有某權限才能使用,如具體允許的權限:/page_base_region.action =perms[“user”],如果要訪問該action,當前登錄用戶必須擁有user名字的權限。? - roles:需要擁有某角色才能使用,如具體允許的角色:/page_base_subarea.action = roles[“operator”]如果要訪問該action,當前用戶必須擁有operator權限。 ### 用戶認證(登錄)—自定義Realm Shiro實現登錄邏輯? 用戶輸入用戶名和密碼 —- 應用程序調用Subject的login方法 —- Subject 調用SecurityManager的方法 —- SecurityManager 調用Realm的認證方法 —- 認證方法根據登錄用戶名查詢密碼 ,返回用戶的密碼 —- SecurityManager 比較用戶輸入的密碼和真實密碼是否一致 。 #### 編寫Shiro的認證登錄邏輯 ~~~ @Action(value="user_login",results={@Result(name=SUCCESS,type="redirect",location="/index.jsp"),@Result(name=LOGIN,location="/login.jsp")}) @InputConfig(resultName="login") public String login() throws Exception { //shrio:登陸邏輯 //獲取認證對象的包裝對象 Subject subject = SecurityUtils.getSubject(); //獲取一個認證的令牌: //直接獲取頁面的用戶和密碼進行校驗 AuthenticationToken authenticationToken = new UsernamePasswordToken(model.getUsername(),MD5Utils.md5(model.getPassword())); //認證過程 try { // 如果成功,就不拋出異常,會自動將用戶放入session的一個屬性 subject.login(authenticationToken); //成功,返回首頁 return SUCCESS; }catch(UnknownAccountException e){ //用戶名錯誤 addActionError(getText("UserAction.usernamenotfound")); //返回登陸頁面 return LOGIN; }catch (IncorrectCredentialsException e) { //密碼錯誤 addActionError(getText("UserAction.passwordinvalid")); //返回登陸頁面 return LOGIN; } catch (AuthenticationException e) { //認證失敗 e.printStackTrace(); //頁面上進行提示 addActionError(getText("UserAction.loginfail")); //返回登陸頁面 return LOGIN; } } ~~~ #### 編寫Realm,給SecurityManager提供 JdbcRealm和jndiLdapRealm,直接連接jdbc或jndi或ldap。? 相當于dao和reaml整合了,能直接讀取數據庫,邏輯代碼都實現好了。 ~~~ /** * 實現認證和授權功能 *自定義的realm,作用從數據庫查詢數據,并返回數據庫認證的信息 */ @Component("bosRealm") public class BosRealm extends AuthorizingRealm{ //注入ehcache的緩存區域 @Value("BosShiroCache")//注入緩存具體對象的名字,該名字在ehcache.xml中配置的 public void setSuperAuthenticationCacheName(String authenticationCacheName){ super.setAuthenticationCacheName(authenticationCacheName); } //注入service @Autowired private UserService userService; //注入角色dao @Autowired private RoleDao roleDao; //注入功能的dao @Autowired private FunctionDao functionDao; //授權方法:獲取用戶的權限信息 //授權:回調方法 //如果返回null,說明沒有權限,shiro會自動跳到<property name="unauthorizedUrl" value="/unauthorized.jsp" /> //如果不返回null,根據配置/page_base_subarea.action = roles["weihu"],去自動匹配 //給授權提供數據的 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //給當前用戶授權的權限(功能權限、角色) SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); //兩種方式: //方式1:工具類來獲取(首長-) // User user=(User)SecurityUtils.getSubject().getPrincipal(); //方式2:通過參數獲取首長(推薦) User user = (User) principals.getPrimaryPrincipal(); //實際:需要根據當前用戶的角色和功能權限來構建一個授權信息對象,交給安全管理器 if (user.getUsername().equals("admin")) { //如果是超級管理員 //查詢出所有的角色,給認證信息對象 List<Role> roleList = roleDao.findAll(); for (Role role : roleList) { authorizationInfo.addRole(role.getCode()); } //查詢出所有的功能權限,給認證對象 List<Function> functionList = functionDao.findAll(); for (Function function : functionList) { authorizationInfo.addStringPermission(function.getCode()); } } else { //如果是普通用戶 List<Role> roleList = roleDao.findByUsers(user); for (Role role : roleList) { authorizationInfo.addRole(role.getCode()); //導航查詢,獲取某角色的擁有的功能權限 Set<Function> functions = role.getFunctions(); for (Function function : functions) { authorizationInfo.addStringPermission(function.getCode()); } } } return authorizationInfo;//將授權信息交給安全管理器接口。 } //認證:回調,認證管理器會將認證令牌放到這里(action層的令牌AuthenticationToken) //發現如果返回null,拋出用戶不存在的異常UnknownAccountException @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //用戶名密碼令牌(action傳過來) UsernamePasswordToken upToken = (UsernamePasswordToken) token; //調用業務層來查詢(根據用戶名來查詢用戶,無需密碼) User user = userService.findByUsername(upToken.getUsername()); //判斷用戶是否存在 if (user == null) { //用戶不存在 return null;//拋出異常 } else { //用戶名存在 //參數1:用戶對象,將來要放入session,數據庫查詢出來的用戶 //參數2:憑證(密碼):密碼校驗:校驗的動作交給shiro //參數3:當前使用的Realm在Spring容器中的名字(bean的名字,自動在spring容器中尋找) SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), super.getName()); return authenticationInfo;//密碼校驗失敗,會自動拋出IncorrectCredentialsException } } } ~~~ ApplicatonContext.xml: ~~~ <!-- service需要spring掃描 --> <context:component-scan base-package="cn.aric.bos.service,cn.aric.bos.web,cn.aric.bos.auth.realm" /> <!-- shiro安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <!-- 注入 Realm連接安全數據--> <property name="realm" ref="bosRealm"></property> <!-- 注入shiro的緩存管理器 --> <property name="cacheManager" ref="shiroCacheManager"/> </bean> ~~~ #### 用戶認證(退出)以及修改密碼 ~~~ /** * 用戶退出登錄 * @return * @throws Exception */ @Action(value="user_logout",results={@Result(name=LOGIN,type="redirect",location="/login.jsp")}) public String logout() throws Exception { //shiro退出 Subject subject = SecurityUtils.getSubject(); subject.logout(); //跳轉登陸頁面 return LOGIN; } /** * 用戶修改密碼 * @return * @throws Exception */ // @Action(value="user_editPassword",results={@Result(name=JSON,type=JSON)}) @Action("user_editPassword") public String editPassword() throws Exception { //獲取Principal就是獲取當前用戶 User loginUser = (User) SecurityUtils.getSubject().getPrincipal(); model.setId(loginUser.getId()); //頁面結果 HashMap<String,Object> resultMap = new HashMap<String,Object>(); try { //調用service進行修改密碼 userService.updateUserPassword(model); //修改成功 resultMap.put("result", true); } catch (Exception e) { e.printStackTrace(); //修改失敗 resultMap.put("result", false); } //將結果壓入棧頂 ActionContext.getContext().getValueStack().push(resultMap); //轉換為json return JSON; } ~~~ #### 用戶授權(授權)—自定義Ream 數據庫數據添加,applicationContext.xml配置 ~~~ <property name="filterChainDefinitions"> <value> /login.jsp = anon /validatecode.jsp = anon /js/** = anon /css/** = anon /images/** = anon /user_login.action = anon /page_base_staff.action = anon /page_base_region.action = perms["region"] /page_base_subarea.action = roles["weihu"] /page_qupai_noticebill_add.action = perms["noticebill"] /page_qupai_quickworkorder.action = roles["kefu"] /** = authc </value> </property> ~~~ 代碼在上面的BosRealm的中,protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals)? RoleDao省略。 ## 方法級別的權限控制 ### 啟用Shiro注解 需要 Shiro 的 Spring AOP 集成來掃描合適的注解類以及執行必要的安全邏輯。? ApplicationContext.xml ~~~ <!-- 開啟權限控制的注解功能并且配置aop --> <!-- 后處理器:通過動態代理在某bean實例化的前增強。:自己去找權限注解 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <!-- 切面自動代理:相當于以前的AOP標簽配置 advisor:切面 advice:通知 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> </bean> <!-- Advisor切面配置:授權屬性的切面 --> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <!-- 注入安全管理器 --> <property name="securityManager" ref="securityManager"/> </bean> ~~~ 在需要權限控制的目標方法上面使用shiro的注解:? @RequiresAuthentication 需要用戶登錄? subject.isAuthenticated() 必須返回true? @ RequiresUser? subject.isAuthenticated() 返回true 或者subject.isRemembered() 返回true? “Remember Me”服務:? 認證機制 基于 session? 被記憶機制 基于 cookie (subject.isAuthenticated() 返回 false ) @ RequiresGuest 與 @RequiresUser 相反,不能認證也不能被記憶。? @ RequiresRoles 需要角色? @RequiresPermissions 需要權限 ### 異常 #### 動態代理異常 解決方案:? 配置ApplicationContext.xml,設置代理為cglib代理(對目標類代理) ~~~ <!-- 切面自動代理:相當于以前的AOP標簽配置 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor" > <!-- 設置aop的代理使用CGLIB代理 --> <property name="proxyTargetClass" value="true"/> </bean> ~~~ 方案二: ~~~ <aop:config proxy-target-class="true" /> ~~~ #### 類型轉換異常 解決方案:遞歸向上尋找泛型的類型。 ~~~ //遞歸向上 查找 Class actionClass =this.getClass(); //向父類遞歸尋找泛型 while(true){ //得到帶有泛型的類型,如BaseAction<Userinfo> Type type = actionClass.getGenericSuperclass(); if(type instanceof ParameterizedType){ //轉換為參數化類型 ParameterizedType parameterizedType = (ParameterizedType) type; //獲取泛型的第一個參數的類型類,如Userinfo Class<T> modelClass = (Class<T>) parameterizedType.getActualTypeArguments()[0]; //實例化模型對象 try { model=modelClass.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } break; } //尋找父類 actionClass=actionClass.getSuperclass(); } ~~~ #### 空指針異常 解決方案1:使用public 的Setter方法上的注解直接注入Service。? SubareaAction: ~~~ //注入service private SubareaService subareaService; @Autowired public void setSubareaService(SubareaService subareaService) { this.subareaService = subareaService; } ~~~ 解決方案2:? @Autowire還放到私有聲明上,? 在struts.xml中覆蓋常量(開啟自動裝配策略):? 值默認是false,struts2默認注入采用的是構造器注入(從spring中尋找的bean)? 改成true,struts2會采用setter方法注入 ## 頁面標簽(實現頁面內容定制顯示) ~~~ <!-- 引入Shiro標簽 --> <%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro"%> ~~~ ![](http://i.imgur.com/h3QSKK8.png) * 頁面拿Session中的user對象: 代表user對象。 * 程序中拿Session中的user對象:SecurityUtils.getSubject().getPrincipal() 資源通配符和權限通配符可便捷開發。 ## 代碼級別 使用代碼編程的方式,直接在程序中使用Subject對象,調用內部的一些API。(有代碼侵入) ~~~ //代碼級別的權限控制(授權):功能權限和角色權限:兩套機制:boolean判斷,異常判斷 //授權的權限控制 //====布爾值判斷 //功能權限 if(subject.isPermitted("staff")){ //必須擁有staff功能權限才能執行代碼 System.out.println("我是一段代碼。。。。。"); } //角色權限 if(subject.hasRole("weihu")){ //必須擁有staff功能權限才能執行代碼 System.out.println("我是一段代碼。。。。。"); } //====異常判斷 //功能權限 try { subject.checkPermission("staff"); //有權限 } catch (AuthorizationException e) { // 沒權限 e.printStackTrace(); } //角色權限 try { subject.checkRole("weihu"); //有權限 } catch (AuthorizationException e) { // 沒權限 e.printStackTrace(); } ~~~
                  <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>

                              哎呀哎呀视频在线观看