国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > Java > 正文

spring boot整合Shiro實(shí)現(xiàn)單點(diǎn)登錄的示例代碼

2024-07-13 10:17:22
字體:
供稿:網(wǎng)友

Shiro是什么

Shiro是一個(gè)Java平臺(tái)的開源權(quán)限框架,用于認(rèn)證和訪問授權(quán)。具體來說,滿足對(duì)如下元素的支持:

  1. 用戶,角色,權(quán)限(僅僅是操作權(quán)限,數(shù)據(jù)權(quán)限必須與業(yè)務(wù)需求緊密結(jié)合),資源(url)。
  2. 用戶分配角色,角色定義權(quán)限。
  3. 訪問授權(quán)時(shí)支持角色或者權(quán)限,并且支持多級(jí)的權(quán)限定義。

Q:對(duì)組的支持?
A:shiro默認(rèn)不支持對(duì)組設(shè)置權(quán)限。

Q:是否可以滿足對(duì)組進(jìn)行角色分配的需求?
A:擴(kuò)展Realm,可以支持對(duì)組進(jìn)行分配角色,其實(shí)就是給該組下的所有用戶分配權(quán)限。

Q:對(duì)數(shù)據(jù)權(quán)限的支持? 在業(yè)務(wù)系統(tǒng)中定義?
A:shiro僅僅實(shí)現(xiàn)對(duì)操作權(quán)限的控制,用于在前端控制元素隱藏或者顯示,以及對(duì)資源訪問權(quán)限進(jìn)行檢查。數(shù)據(jù)權(quán)限與具體的業(yè)務(wù)需求緊密關(guān)聯(lián),shiro本身無法實(shí)現(xiàn)對(duì)數(shù)據(jù)權(quán)限的控制。

Q:動(dòng)態(tài)權(quán)限分配?
A:擴(kuò)展org.apache.shiro.realm.Realm,支持動(dòng)態(tài)權(quán)限分配。

Q:與Spring集成?
A:可以支持與Spring集成,shiro還支持jsp標(biāo)簽。

前面的博客中,我們說道了Shiro的兩個(gè)最大的特點(diǎn),認(rèn)證和授權(quán),而單點(diǎn)登錄也是屬于認(rèn)證的一部分,默認(rèn)情況下,Shiro已經(jīng)為我們實(shí)現(xiàn)了和Cas的集成,我們加入集成的一些配置就ok了。

1、加入shiro-cas包

<!-- shiro整合cas單點(diǎn) -->     <dependency>       <groupId>org.apache.shiro</groupId>       <artifactId>shiro-cas</artifactId>       <version>1.2.4</version>     </dependency> 

2、加入單點(diǎn)登錄的配置

這里,我將所有的配置都貼出來,方便參考,配置里面已經(jīng)加了詳盡的說明。

package com.chhliu.springboot.shiro.config;  import java.util.LinkedHashMap; import java.util.Map; import javax.servlet.Filter; import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.cas.CasFilter; import org.apache.shiro.cas.CasSubjectFactory; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.jasig.cas.client.session.SingleSignOutFilter; import org.jasig.cas.client.session.SingleSignOutHttpSessionListener; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletListenerRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.web.filter.DelegatingFilterProxy;  /**  * Shiro 配置  *  * Apache Shiro 核心通過 Filter 來實(shí)現(xiàn),就好像SpringMvc 通過DispachServlet 來主控制一樣。 既然是使用  * Filter 一般也就能猜到,是通過URL規(guī)則來進(jìn)行過濾和權(quán)限校驗(yàn),所以我們需要定義一系列關(guān)于URL的規(guī)則和訪問權(quán)限。  *  * @author chhliu  */ @Configuration public class ShiroConfiguration {      // cas server地址   public static final String casServerUrlPrefix = "http://127.0.0.1";   // Cas登錄頁面地址   public static final String casLoginUrl = casServerUrlPrefix + "/login";   // Cas登出頁面地址   public static final String casLogoutUrl = casServerUrlPrefix + "/logout";   // 當(dāng)前工程對(duì)外提供的服務(wù)地址   public static final String shiroServerUrlPrefix = "http://127.0.1.28:8080";   // casFilter UrlPattern   public static final String casFilterUrlPattern = "/index";   // 登錄地址   public static final String loginUrl = casLoginUrl + "?service=" + shiroServerUrlPrefix + casFilterUrlPattern;   // 登出地址(casserver啟用service跳轉(zhuǎn)功能,需在webapps/cas/WEB-INF/cas.properties文件中啟用cas.logout.followServiceRedirects=true)   public static final String logoutUrl = casLogoutUrl+"?service="+loginUrl;   // 登錄成功地址 //  public static final String loginSuccessUrl = "/index";   // 權(quán)限認(rèn)證失敗跳轉(zhuǎn)地址   public static final String unauthorizedUrl = "/error/403.html";      /**    * 實(shí)例化SecurityManager,該類是shiro的核心類    * @return    */   @Bean   public DefaultWebSecurityManager securityManager() {     DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();     securityManager.setRealm(myShiroCasRealm()); //   <!-- 用戶授權(quán)/認(rèn)證信息Cache, 采用EhCache 緩存 -->     securityManager.setCacheManager(getEhCacheManager());     // 指定 SubjectFactory,如果要實(shí)現(xiàn)cas的remember me的功能,需要用到下面這個(gè)CasSubjectFactory,并設(shè)置到securityManager的subjectFactory中     securityManager.setSubjectFactory(new CasSubjectFactory());     return securityManager;   }    /**    * 配置緩存    * @return    */   @Bean   public EhCacheManager getEhCacheManager() {     EhCacheManager em = new EhCacheManager();     em.setCacheManagerConfigFile("classpath:config/ehcache-shiro.xml");     return em;   }    /**    * 配置Realm,由于我們使用的是CasRealm,所以已經(jīng)集成了單點(diǎn)登錄的功能    * @param cacheManager    * @return    */   @Bean   public MyShiroRealm myShiroCasRealm() {     MyShiroRealm realm = new MyShiroRealm();     // cas登錄服務(wù)器地址前綴     realm.setCasServerUrlPrefix(ShiroConfiguration.casServerUrlPrefix);     // 客戶端回調(diào)地址,登錄成功后的跳轉(zhuǎn)地址(自己的服務(wù)地址)     realm.setCasService(ShiroConfiguration.shiroServerUrlPrefix + ShiroConfiguration.casFilterUrlPattern);     // 登錄成功后的默認(rèn)角色,此處默認(rèn)為user角色     realm.setDefaultRoles("user");     return realm;   }    /**    * 注冊(cè)單點(diǎn)登出的listener    * @return    */   @SuppressWarnings({ "rawtypes", "unchecked" })   @Bean   @Order(Ordered.HIGHEST_PRECEDENCE)// 優(yōu)先級(jí)需要高于Cas的Filter   public ServletListenerRegistrationBean<?> singleSignOutHttpSessionListener(){     ServletListenerRegistrationBean bean = new ServletListenerRegistrationBean();     bean.setListener(new SingleSignOutHttpSessionListener());     bean.setEnabled(true);     return bean;   }    /**    * 注冊(cè)單點(diǎn)登出filter    * @return    */   @Bean   public FilterRegistrationBean singleSignOutFilter(){     FilterRegistrationBean bean = new FilterRegistrationBean();     bean.setName("singleSignOutFilter");     bean.setFilter(new SingleSignOutFilter());     bean.addUrlPatterns("/*");     bean.setEnabled(true);     return bean;   }    /**    * 注冊(cè)DelegatingFilterProxy(Shiro)    */   @Bean   public FilterRegistrationBean delegatingFilterProxy() {     FilterRegistrationBean filterRegistration = new FilterRegistrationBean();     filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));     // 該值缺省為false,表示生命周期由SpringApplicationContext管理,設(shè)置為true則表示由ServletContainer管理     filterRegistration.addInitParameter("targetFilterLifecycle", "true");     filterRegistration.setEnabled(true);     filterRegistration.addUrlPatterns("/*");     return filterRegistration;   }    /**    * 該類可以保證實(shí)現(xiàn)了org.apache.shiro.util.Initializable接口的shiro對(duì)象的init或者是destory方法被自動(dòng)調(diào)用,    * 而不用手動(dòng)指定init-method或者是destory-method方法    * 注意:如果使用了該類,則不需要手動(dòng)指定初始化方法和銷毀方法,否則會(huì)出錯(cuò)    * @return    */   @Bean(name = "lifecycleBeanPostProcessor")   public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {     return new LifecycleBeanPostProcessor();   }    /**    * 下面兩個(gè)配置主要用來開啟shiro aop注解支持. 使用代理方式;所以需要開啟代碼支持;    * @return    */   @Bean   @DependsOn("lifecycleBeanPostProcessor")   public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {     DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();     daap.setProxyTargetClass(true);     return daap;   }      /**    * @param securityManager    * @return    */   @Bean   public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {     AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();     authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);     return authorizationAttributeSourceAdvisor;   }    /**    * CAS過濾器    * @return    */   @Bean(name = "casFilter")   public CasFilter getCasFilter() {     CasFilter casFilter = new CasFilter();     casFilter.setName("casFilter");     casFilter.setEnabled(true);     // 登錄失敗后跳轉(zhuǎn)的URL,也就是 Shiro 執(zhí)行 CasRealm 的 doGetAuthenticationInfo 方法向CasServer驗(yàn)證tiket     casFilter.setFailureUrl(loginUrl);// 我們選擇認(rèn)證失敗后再打開登錄頁面     casFilter.setLoginUrl(loginUrl);     return casFilter;   }    /**    * 使用工廠模式,創(chuàng)建并初始化ShiroFilter    * @param securityManager    * @param casFilter    * @return    */   @Bean(name = "shiroFilter")   public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager, CasFilter casFilter) {     ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();     // 必須設(shè)置 SecurityManager     shiroFilterFactoryBean.setSecurityManager(securityManager);     // 如果不設(shè)置默認(rèn)會(huì)自動(dòng)尋找Web工程根目錄下的"/login.jsp"頁面     shiroFilterFactoryBean.setLoginUrl(loginUrl);     /*      * 登錄成功后要跳轉(zhuǎn)的連接,不設(shè)置的時(shí)候,會(huì)默認(rèn)跳轉(zhuǎn)到前一步的url      * 比如先在瀏覽器中輸入了http://localhost:8080/userlist,但是現(xiàn)在用戶卻沒有登錄,于是會(huì)跳轉(zhuǎn)到登錄頁面,等登錄認(rèn)證通過后,      * 頁面會(huì)再次自動(dòng)跳轉(zhuǎn)到http://localhost:8080/userlist頁面而不是登錄成功后的index頁面      * 建議不要設(shè)置這個(gè)字段      */ //    shiroFilterFactoryBean.setSuccessUrl(loginSuccessUrl);          // 設(shè)置無權(quán)限訪問頁面     shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl);     /*      * 添加casFilter到shiroFilter中,注意,casFilter需要放到shiroFilter的前面,      * 從而保證程序在進(jìn)入shiro的login登錄之前就會(huì)進(jìn)入單點(diǎn)認(rèn)證      */     Map<String, Filter> filters = new LinkedHashMap<>();     filters.put("casFilter", casFilter);          // logout已經(jīng)被單點(diǎn)登錄的logout取代     // filters.put("logout",logoutFilter());     shiroFilterFactoryBean.setFilters(filters);      loadShiroFilterChain(shiroFilterFactoryBean);     return shiroFilterFactoryBean;   }    /**    * 加載shiroFilter權(quán)限控制規(guī)則(從數(shù)據(jù)庫讀取然后配置),角色/權(quán)限信息由MyShiroCasRealm對(duì)象提供doGetAuthorizationInfo實(shí)現(xiàn)獲取來的    * 生產(chǎn)中會(huì)將這部分規(guī)則放到數(shù)據(jù)庫中    * @param shiroFilterFactoryBean    */   private void loadShiroFilterChain(ShiroFilterFactoryBean shiroFilterFactoryBean){     /////////////////////// 下面這些規(guī)則配置最好配置到配置文件中,注意,此處加入的filter需要保證有序,所以用的LinkedHashMap ///////////////////////     Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();      filterChainDefinitionMap.put(casFilterUrlPattern, "casFilter");      //2.不攔截的請(qǐng)求     filterChainDefinitionMap.put("/css/**","anon");     filterChainDefinitionMap.put("/js/**","anon");     filterChainDefinitionMap.put("/login", "anon");     // 此處將logout頁面設(shè)置為anon,而不是logout,因?yàn)閘ogout被單點(diǎn)處理,而不需要再被shiro的logoutFilter進(jìn)行攔截     filterChainDefinitionMap.put("/logout","anon");     filterChainDefinitionMap.put("/error","anon");     //3.攔截的請(qǐng)求(從本地?cái)?shù)據(jù)庫獲取或者從casserver獲取(webservice,http等遠(yuǎn)程方式),看你的角色權(quán)限配置在哪里)     filterChainDefinitionMap.put("/user", "authc"); //需要登錄     //4.登錄過的不攔截     filterChainDefinitionMap.put("/**", "authc");     shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);   } } 

部分配置參考:http://shiro.apache.org/spring.html

3、編寫Realm

由于需要集成單點(diǎn)登錄的功能,所以需要集成CasRealm類,該類已經(jīng)為我們實(shí)現(xiàn)了單點(diǎn)認(rèn)證的功能,我們要做的就是實(shí)現(xiàn)授權(quán)部分的功能,示例代碼如下:

package com.chhliu.springboot.shiro.config;  import javax.annotation.Resource;  import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.cas.CasRealm; import org.apache.shiro.subject.PrincipalCollection;  import com.chhliu.springboot.shiro.mode.SysPermission; import com.chhliu.springboot.shiro.mode.SysRole; import com.chhliu.springboot.shiro.mode.UserInfo; import com.chhliu.springboot.shiro.service.UserInfoService;  /**  * 權(quán)限校驗(yàn)核心類; 由于使用了單點(diǎn)登錄,所以無需再進(jìn)行身份認(rèn)證 只需要授權(quán)即可  *  * @author chhliu  */ public class MyShiroRealm extends CasRealm {    @Resource   private UserInfoService userInfoService;    /**    * 1、CAS認(rèn)證 ,驗(yàn)證用戶身份    * 2、將用戶基本信息設(shè)置到會(huì)話中,方便獲取    * 3、該方法可以直接使用CasRealm中的認(rèn)證方法,此處僅用作測(cè)試    */   @Override   protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {      // 調(diào)用父類中的認(rèn)證方法,CasRealm已經(jīng)為我們實(shí)現(xiàn)了單點(diǎn)認(rèn)證。     AuthenticationInfo authc = super.doGetAuthenticationInfo(token);      // 獲取登錄的賬號(hào),cas認(rèn)證成功后,會(huì)將賬號(hào)存起來     String account = (String) authc.getPrincipals().getPrimaryPrincipal();      // 將用戶信息存入session中,方便程序獲取,此處可以將根據(jù)登錄賬號(hào)查詢出的用戶信息放到session中     SecurityUtils.getSubject().getSession().setAttribute("no", account);      return authc;   }    /**    * 此方法調(diào)用 hasRole,hasPermission的時(shí)候才會(huì)進(jìn)行回調(diào).    *    * 權(quán)限信息.(授權(quán)): 1、如果用戶正常退出,緩存自動(dòng)清空; 2、如果用戶非正常退出,緩存自動(dòng)清空;    * 3、如果我們修改了用戶的權(quán)限,而用戶不退出系統(tǒng),修改的權(quán)限無法立即生效。 (需要手動(dòng)編程進(jìn)行實(shí)現(xiàn);放在service進(jìn)行調(diào)用)    * 在權(quán)限修改后調(diào)用realm中的方法,realm已經(jīng)由spring管理,所以從spring中獲取realm實(shí)例, 調(diào)用clearCached方法;    * :Authorization 是授權(quán)訪問控制,用于對(duì)用戶進(jìn)行的操作授權(quán),證明該用戶是否允許進(jìn)行當(dāng)前操作,如訪問某個(gè)鏈接,某個(gè)資源文件等。    *    * @param principals    * @return    */   @Override   protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {     System.out.println("權(quán)限配置-->MyShiroRealm.doGetAuthorizationInfo()");      SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();     // 獲取單點(diǎn)登陸后的用戶名,也可以從session中獲取,因?yàn)樵谡J(rèn)證成功后,已經(jīng)將用戶名放到session中去了     String userName = (String) super.getAvailablePrincipal(principals); //       principals.getPrimaryPrincipal(); 這種方式也可以獲取用戶名      // 根據(jù)用戶名獲取該用戶的角色和權(quán)限信息     UserInfo userInfo = userInfoService.findByUsername(userName);      // 將用戶對(duì)應(yīng)的角色和權(quán)限信息打包放到AuthorizationInfo中     for (SysRole role : userInfo.getRoleList()) {       authorizationInfo.addRole(role.getRole());       for (SysPermission p : role.getPermissions()) {         authorizationInfo.addStringPermission(p.getPermission());       }     }      return authorizationInfo;   } } 

下面,我們就可以進(jìn)行驗(yàn)證測(cè)試了!

在瀏覽器輸入http:127.0.1.28:8080/userInfo/userList 我們會(huì)發(fā)現(xiàn),會(huì)自動(dòng)跳轉(zhuǎn)到單點(diǎn)的登錄頁面

spring,boot,Shiro,單點(diǎn)登錄

然后我們輸入用戶名和密碼,就會(huì)自動(dòng)跳轉(zhuǎn)到http:127.0.1.28:8080/userInfo/userList頁面了。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持VeVb武林網(wǎng)。


注:相關(guān)教程知識(shí)閱讀請(qǐng)移步到JAVA教程頻道。
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 公安县| 凤山县| 凉城县| 龙陵县| 洞头县| 乐业县| 南丹县| 石首市| 山西省| 新河县| 灌阳县| 新昌县| 呈贡县| 镇宁| 宜春市| 祁东县| 休宁县| 扬州市| 偏关县| 福州市| 长海县| 衡水市| 木里| 蒙自县| 都安| 噶尔县| 吉安市| 特克斯县| 沐川县| 泽普县| 乌兰浩特市| 繁峙县| 阿荣旗| 青州市| 紫阳县| 那坡县| 白城市| 多伦县| 南乐县| 吉木萨尔县| 新密市|