中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

spring boot整合Shiro實現單點登錄的示例代碼

發布時間:2020-10-13 19:32:05 來源:腳本之家 閱讀:355 作者:牛奮lch 欄目:編程語言

Shiro是什么

Shiro是一個Java平臺的開源權限框架,用于認證和訪問授權。具體來說,滿足對如下元素的支持:

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

Q:對組的支持?
A:shiro默認不支持對組設置權限。

Q:是否可以滿足對組進行角色分配的需求?
A:擴展Realm,可以支持對組進行分配角色,其實就是給該組下的所有用戶分配權限。

Q:對數據權限的支持? 在業務系統中定義?
A:shiro僅僅實現對操作權限的控制,用于在前端控制元素隱藏或者顯示,以及對資源訪問權限進行檢查。數據權限與具體的業務需求緊密關聯,shiro本身無法實現對數據權限的控制。

Q:動態權限分配?
A:擴展org.apache.shiro.realm.Realm,支持動態權限分配。

Q:與Spring集成?
A:可以支持與Spring集成,shiro還支持jsp標簽。

前面的博客中,我們說道了Shiro的兩個最大的特點,認證和授權,而單點登錄也是屬于認證的一部分,默認情況下,Shiro已經為我們實現了和Cas的集成,我們加入集成的一些配置就ok了。

1、加入shiro-cas包

<!-- shiro整合cas單點 --> 
    <dependency> 
      <groupId>org.apache.shiro</groupId> 
      <artifactId>shiro-cas</artifactId> 
      <version>1.2.4</version> 
    </dependency> 

2、加入單點登錄的配置

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

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 來實現,就好像SpringMvc 通過DispachServlet 來主控制一樣。 既然是使用 
 * Filter 一般也就能猜到,是通過URL規則來進行過濾和權限校驗,所以我們需要定義一系列關于URL的規則和訪問權限。 
 * 
 * @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"; 
  // 當前工程對外提供的服務地址 
  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跳轉功能,需在webapps\cas\WEB-INF\cas.properties文件中啟用cas.logout.followServiceRedirects=true) 
  public static final String logoutUrl = casLogoutUrl+"?service="+loginUrl; 
  // 登錄成功地址 
//  public static final String loginSuccessUrl = "/index"; 
  // 權限認證失敗跳轉地址 
  public static final String unauthorizedUrl = "/error/403.html"; 
   
  /** 
   * 實例化SecurityManager,該類是shiro的核心類 
   * @return 
   */ 
  @Bean 
  public DefaultWebSecurityManager securityManager() { 
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); 
    securityManager.setRealm(myShiroCasRealm()); 
//   <!-- 用戶授權/認證信息Cache, 采用EhCache 緩存 --> 
    securityManager.setCacheManager(getEhCacheManager()); 
    // 指定 SubjectFactory,如果要實現cas的remember me的功能,需要用到下面這個CasSubjectFactory,并設置到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,所以已經集成了單點登錄的功能 
   * @param cacheManager 
   * @return 
   */ 
  @Bean 
  public MyShiroRealm myShiroCasRealm() { 
    MyShiroRealm realm = new MyShiroRealm(); 
    // cas登錄服務器地址前綴 
    realm.setCasServerUrlPrefix(ShiroConfiguration.casServerUrlPrefix); 
    // 客戶端回調地址,登錄成功后的跳轉地址(自己的服務地址) 
    realm.setCasService(ShiroConfiguration.shiroServerUrlPrefix + ShiroConfiguration.casFilterUrlPattern); 
    // 登錄成功后的默認角色,此處默認為user角色 
    realm.setDefaultRoles("user"); 
    return realm; 
  } 
 
  /** 
   * 注冊單點登出的listener 
   * @return 
   */ 
  @SuppressWarnings({ "rawtypes", "unchecked" }) 
  @Bean 
  @Order(Ordered.HIGHEST_PRECEDENCE)// 優先級需要高于Cas的Filter 
  public ServletListenerRegistrationBean<?> singleSignOutHttpSessionListener(){ 
    ServletListenerRegistrationBean bean = new ServletListenerRegistrationBean(); 
    bean.setListener(new SingleSignOutHttpSessionListener()); 
    bean.setEnabled(true); 
    return bean; 
  } 
 
  /** 
   * 注冊單點登出filter 
   * @return 
   */ 
  @Bean 
  public FilterRegistrationBean singleSignOutFilter(){ 
    FilterRegistrationBean bean = new FilterRegistrationBean(); 
    bean.setName("singleSignOutFilter"); 
    bean.setFilter(new SingleSignOutFilter()); 
    bean.addUrlPatterns("/*"); 
    bean.setEnabled(true); 
    return bean; 
  } 
 
  /** 
   * 注冊DelegatingFilterProxy(Shiro) 
   */ 
  @Bean 
  public FilterRegistrationBean delegatingFilterProxy() { 
    FilterRegistrationBean filterRegistration = new FilterRegistrationBean(); 
    filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter")); 
    // 該值缺省為false,表示生命周期由SpringApplicationContext管理,設置為true則表示由ServletContainer管理 
    filterRegistration.addInitParameter("targetFilterLifecycle", "true"); 
    filterRegistration.setEnabled(true); 
    filterRegistration.addUrlPatterns("/*"); 
    return filterRegistration; 
  } 
 
  /** 
   * 該類可以保證實現了org.apache.shiro.util.Initializable接口的shiro對象的init或者是destory方法被自動調用, 
   * 而不用手動指定init-method或者是destory-method方法 
   * 注意:如果使用了該類,則不需要手動指定初始化方法和銷毀方法,否則會出錯 
   * @return 
   */ 
  @Bean(name = "lifecycleBeanPostProcessor") 
  public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() { 
    return new LifecycleBeanPostProcessor(); 
  } 
 
  /** 
   * 下面兩個配置主要用來開啟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); 
    // 登錄失敗后跳轉的URL,也就是 Shiro 執行 CasRealm 的 doGetAuthenticationInfo 方法向CasServer驗證tiket 
    casFilter.setFailureUrl(loginUrl);// 我們選擇認證失敗后再打開登錄頁面 
    casFilter.setLoginUrl(loginUrl); 
    return casFilter; 
  } 
 
  /** 
   * 使用工廠模式,創建并初始化ShiroFilter 
   * @param securityManager 
   * @param casFilter 
   * @return 
   */ 
  @Bean(name = "shiroFilter") 
  public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager, CasFilter casFilter) { 
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); 
    // 必須設置 SecurityManager 
    shiroFilterFactoryBean.setSecurityManager(securityManager); 
    // 如果不設置默認會自動尋找Web工程根目錄下的"/login.jsp"頁面 
    shiroFilterFactoryBean.setLoginUrl(loginUrl); 
    /* 
     * 登錄成功后要跳轉的連接,不設置的時候,會默認跳轉到前一步的url 
     * 比如先在瀏覽器中輸入了http://localhost:8080/userlist,但是現在用戶卻沒有登錄,于是會跳轉到登錄頁面,等登錄認證通過后, 
     * 頁面會再次自動跳轉到http://localhost:8080/userlist頁面而不是登錄成功后的index頁面 
     * 建議不要設置這個字段 
     */ 
//    shiroFilterFactoryBean.setSuccessUrl(loginSuccessUrl); 
     
    // 設置無權限訪問頁面 
    shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl); 
    /* 
     * 添加casFilter到shiroFilter中,注意,casFilter需要放到shiroFilter的前面, 
     * 從而保證程序在進入shiro的login登錄之前就會進入單點認證 
     */ 
    Map<String, Filter> filters = new LinkedHashMap<>(); 
    filters.put("casFilter", casFilter); 
     
    // logout已經被單點登錄的logout取代 
    // filters.put("logout",logoutFilter()); 
    shiroFilterFactoryBean.setFilters(filters); 
 
    loadShiroFilterChain(shiroFilterFactoryBean); 
    return shiroFilterFactoryBean; 
  } 
 
  /** 
   * 加載shiroFilter權限控制規則(從數據庫讀取然后配置),角色/權限信息由MyShiroCasRealm對象提供doGetAuthorizationInfo實現獲取來的 
   * 生產中會將這部分規則放到數據庫中 
   * @param shiroFilterFactoryBean 
   */ 
  private void loadShiroFilterChain(ShiroFilterFactoryBean shiroFilterFactoryBean){ 
    /////////////////////// 下面這些規則配置最好配置到配置文件中,注意,此處加入的filter需要保證有序,所以用的LinkedHashMap /////////////////////// 
    Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();  
    filterChainDefinitionMap.put(casFilterUrlPattern, "casFilter");  
    //2.不攔截的請求 
    filterChainDefinitionMap.put("/css/**","anon"); 
    filterChainDefinitionMap.put("/js/**","anon"); 
    filterChainDefinitionMap.put("/login", "anon"); 
    // 此處將logout頁面設置為anon,而不是logout,因為logout被單點處理,而不需要再被shiro的logoutFilter進行攔截 
    filterChainDefinitionMap.put("/logout","anon"); 
    filterChainDefinitionMap.put("/error","anon"); 
    //3.攔截的請求(從本地數據庫獲取或者從casserver獲取(webservice,http等遠程方式),看你的角色權限配置在哪里) 
    filterChainDefinitionMap.put("/user", "authc"); //需要登錄 
    //4.登錄過的不攔截 
    filterChainDefinitionMap.put("/**", "authc"); 
    shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); 
  } 
} 

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

3、編寫Realm

由于需要集成單點登錄的功能,所以需要集成CasRealm類,該類已經為我們實現了單點認證的功能,我們要做的就是實現授權部分的功能,示例代碼如下:

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

下面,我們就可以進行驗證測試了!

在瀏覽器輸入http:127.0.1.28:8080/userInfo/userList 我們會發現,會自動跳轉到單點的登錄頁面

spring boot整合Shiro實現單點登錄的示例代碼

然后我們輸入用戶名和密碼,就會自動跳轉到http:127.0.1.28:8080/userInfo/userList頁面了。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

虞城县| 鄂温| 乌拉特中旗| 鄯善县| 佛坪县| 浦北县| 溧阳市| 隆化县| 滨州市| 长春市| 治县。| 正安县| 屏南县| 阳山县| 潞西市| 兖州市| 介休市| 赤峰市| 多伦县| 广丰县| 寻乌县| 周口市| 梅河口市| 南丰县| 齐齐哈尔市| 贺州市| 托里县| 吉木萨尔县| 麦盖提县| 扬州市| 滕州市| 常宁市| 汾西县| 蕉岭县| 中江县| 泰和县| 乌鲁木齐市| 高要市| 海晏县| 扶沟县| 镇康县|