一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - spring boot整合Shiro實(shí)現(xiàn)單點(diǎn)登錄的示例代碼

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

2021-03-27 13:43牛奮lch Java教程

本篇文章主要介紹了spring boot整合Shiro實(shí)現(xiàn)單點(diǎn)登錄的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

Shiro是什么

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

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

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

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

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

?
1
2
3
4
5
6
<!-- 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)加了詳盡的說明。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
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)前工程對外提供的服務(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;
  }
 
  /**
   * 注冊單點(diǎn)登出的listener
   * @return
   */
  @SuppressWarnings({ "rawtypes", "unchecked" })
  @Bean
  @Order(Ordered.HIGHEST_PRECEDENCE)// 優(yōu)先級需要高于Cas的Filter
  public ServletListenerRegistrationBean<?> singleSignOutHttpSessionListener(){
    ServletListenerRegistrationBean bean = new ServletListenerRegistrationBean();
    bean.setListener(new SingleSignOutHttpSessionListener());
    bean.setEnabled(true);
    return bean;
  }
 
  /**
   * 注冊單點(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;
  }
 
  /**
   * 注冊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對象的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對象提供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.不攔截的請求
    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.攔截的請求(從本地?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)部分的功能,示例代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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)證方法,此處僅用作測試
   */
  @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);
 
    // 獲取登錄的賬號,cas認(rèn)證成功后,會(huì)將賬號存起來
    String account = (String) authc.getPrincipals().getPrimaryPrincipal();
 
    // 將用戶信息存入session中,方便程序獲取,此處可以將根據(jù)登錄賬號查詢出的用戶信息放到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)訪問控制,用于對用戶進(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);
 
    // 將用戶對應(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)證測試了!

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

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

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

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。

原文鏈接:http://blog.csdn.net/liuchuanhong1/article/details/76850181

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 亚洲图片一区二区三区 | 169pp美女| xxxx在线视频| 国产成人+亚洲欧洲 | www免费看 | 第一福利在线观看永久视频 | 男女小视频在线观看 | 亚洲好骚综合 | 亚洲 欧美 中文 日韩 另类 | 国产视频一区二 | 男人午夜禁片在线观看 | 天天综合色天天综合网 | 久久久久久久国产精品视频 | 亚洲成a人片777777久久 | 国产精品久久久久久 | 近亲乱中文字幕 | 亚洲一级特黄特黄的大片 | 大象传媒2021秘密入口 | 亚洲精品第五页中文字幕 | 高清国产在线观看 | 成人香蕉xxxxxxx | sao虎在线精品永久 s0e一923春菜花在线播放 | 美女的让男人桶爽网站 | 国产一级视频久久 | 男女姓交大视频免费观看 | 亚洲激情久久 | 大jjjj免费看视频 | 男人好大好硬好爽免费视频 | 秋霞在线一级 | voyeur 中国女厕 亚洲女厕 | www.亚洲视频 | 无限国产资源 | 我将她侵犯1~6樱花动漫在线看 | 三级理论在线观看 | 色综合色狠狠天天久久婷婷基地 | 亚洲精品第五页 | 好吊色视频988gao在线观看 | 青青青国产精品国产精品久久久久 | 特级一级全黄毛片免费 | 美女靠逼免费网站 | 韩国一大片a毛片女同 |