springboot整合shiro和session的详细过程和自定义登录拦截器
文章目錄
- 1.shiro依賴
- 2.shiro配置
- shiro過濾器配置:
- 關(guān)聯(lián)自定義的其他管理器
- 自定義會(huì)話工廠:
- 3.登陸時(shí)記錄用戶信息
- 4.shiro一些工具類的學(xué)習(xí)
- 5.自定義登錄攔截器
shiro是一個(gè)安全框架,用于認(rèn)證和授權(quán),我覺得與springsecurity相比它上手更容易,同時(shí)如果是簡單的登錄攔截也可以用登錄攔截器實(shí)現(xiàn),下面先進(jìn)行springboot整合 shiro的過程
1.shiro依賴
<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.7.1</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.7.1</version></dependency>2.shiro配置
配置安全管理器:SecurityManager
Authenticator 的職責(zé)是驗(yàn)證用戶帳號(hào),是ShiroAPI 中身份驗(yàn)證核心的入口點(diǎn):如果驗(yàn)證成功,將返回AuthenticationInfo驗(yàn)證信息;此信息中包含了身份及憑證;如果驗(yàn)證失敗將拋出相應(yīng)的AuthenticationException異常
?SecurityManager接口繼承了Authenticator,另外還有一個(gè)ModularRealmAuthenticator實(shí)現(xiàn),其委托給多個(gè)Realm 進(jìn)行驗(yàn)證,驗(yàn)證規(guī)則通過AuthenticationStrategy接口指定
哪些url是需要攔截的,哪些是不需要攔截的,登錄頁面、登錄成功頁面的url、自定義的Realm等這些信息需要設(shè)置到Shiro中
shiro過濾器配置:
/*** Shiro過濾器配置*/@Beanpublic ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();// Shiro的核心安全接口,這個(gè)屬性是必須的shiroFilterFactoryBean.setSecurityManager(securityManager);// 身份認(rèn)證失敗,則跳轉(zhuǎn)到登錄頁面的配置shiroFilterFactoryBean.setLoginUrl(loginUrl);// 權(quán)限認(rèn)證失敗,則跳轉(zhuǎn)到指定頁面shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl);// Shiro連接約束配置,即過濾鏈的定義LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();// 對(duì)靜態(tài)資源設(shè)置匿名訪問filterChainDefinitionMap.put("/favicon.ico**", "anon");//加入自己的路徑和訪問權(quán)限// 系統(tǒng)權(quán)限列表// filterChainDefinitionMap.putAll(SpringUtils.getBean(IMenuService.class).selectPermsAll());Map<String, Filter> filters = new LinkedHashMap<String, Filter>();filters.put("onlineSession", onlineSessionFilter());filters.put("syncOnlineSession", syncOnlineSessionFilter());filters.put("captchaValidate", captchaValidateFilter());filters.put("kickout", kickoutSessionFilter());// 注銷成功,則跳轉(zhuǎn)到指定頁面filters.put("logout", logoutFilter());shiroFilterFactoryBean.setFilters(filters);// 所有請(qǐng)求需要認(rèn)證filterChainDefinitionMap.put("/**", "user,kickout,onlineSession,syncOnlineSession");shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);return shiroFilterFactoryBean;}安全管理器關(guān)聯(lián)自己的Realm
@Bean(name="security")public DefaultWebSecurityManager getDefaultManager(@Qualifier("realm")UserRealm userRealm){DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();//關(guān)聯(lián)自己的realmdefaultSecurityManager.setRealm(userRealm);return defaultSecurityManager;}@Bean(name = "realm")//創(chuàng)建realm對(duì)象public UserRealm userRealm(){return new UserRealm();}關(guān)聯(lián)自定義的其他管理器
@Beanpublic SecurityManager securityManager(UserRealm userRealm){DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();// 設(shè)置realm.securityManager.setRealm(userRealm);// 記住我securityManager.setRememberMeManager(rememberMe ? rememberMeManager() : null);// 注入緩存管理器;securityManager.setCacheManager(getEhCacheManager());// session管理器securityManager.setSessionManager(sessionManager());return securityManager;}/*** 緩存管理器 使用Ehcache實(shí)現(xiàn)*/@Beanpublic EhCacheManager getEhCacheManager(){net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager("ruoyi");EhCacheManager em = new EhCacheManager();if (StringUtils.isNull(cacheManager)){em.setCacheManager(new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream()));return em;}else{em.setCacheManager(cacheManager);return em;}}緩存:Shiro內(nèi)部相應(yīng)的組件(DefaultSecurityManager)會(huì)自動(dòng)檢測(cè)相應(yīng)的對(duì)象(如Realm)是否實(shí)現(xiàn)了CacheManagerAware并自動(dòng)注入相應(yīng)的CacheManager。
Shiro提供了CachingRealm,其實(shí)現(xiàn)了CacheManagerAware接口,提供了緩存的一些基礎(chǔ)實(shí)現(xiàn);
?AuthenticatingRealm及AuthorizingRealm也分別提供了對(duì)AuthenticationInfo和AuthorizationInfo信息的緩存。
Session 緩存
?如SecurityManager實(shí)現(xiàn)了SessionSecurityManager,其會(huì)判斷SessionManager是否實(shí)現(xiàn)了CacheManagerAware接口,如果實(shí)現(xiàn)了會(huì)把CacheManager設(shè)置給它。
?SessionManager也會(huì)判斷相應(yīng)的SessionDAO(如繼承自CachingSessionDAO)是否實(shí)現(xiàn)了CacheManagerAware,如果實(shí)現(xiàn)了會(huì)把CacheManager設(shè)置給它
?設(shè)置了緩存的SessionManager,查詢時(shí)會(huì)先查緩存,如果找不到才查數(shù)據(jù)庫。
自定義會(huì)話工廠:
//自定義sessionFactory會(huì)話 @Component public class OnlineSessionFactory implements SessionFactory {@Overridepublic Session createSession(SessionContext initData){OnlineSession session = new OnlineSession();if (initData != null && initData instanceof WebSessionContext){WebSessionContext sessionContext = (WebSessionContext) initData;HttpServletRequest request = (HttpServletRequest) sessionContext.getServletRequest();if (request != null){UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));// 獲取客戶端操作系統(tǒng)String os = userAgent.getOperatingSystem().getName();// 獲取客戶端瀏覽器String browser = userAgent.getBrowser().getName();session.setHost(IpUtils.getIpAddr(request));session.setBrowser(browser);session.setOs(os);}}return session;} }3.登陸時(shí)記錄用戶信息
在控制器層:
@ApiOperation(value="登錄") @PostMapping("/login")public ResponseResult<User> toLogin(@ApiParam(name="用戶對(duì)象",value="傳入json格式",required=true)LoginForm loginForm) {User user = userService.selectUserByLoginName(loginForm.getUserName(),loginForm.getPassword(), false);if (user != null) {UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(),user.getPassword(), false);Subject subject = SecurityUtils.getSubject(); subject.login(token); return ResponseResult.success();}else return ResponseResult.error(); }4.shiro一些工具類的學(xué)習(xí)
SecurityUtils.getSubject()是每個(gè)請(qǐng)求創(chuàng)建一個(gè)Subject, 并保存到ThreadContext的resources(ThreadLocal<Map<Object, Object>>)變量中,也就是一個(gè)http請(qǐng)求一個(gè)subject,并綁定到當(dāng)前線程。
subject.login()登陸認(rèn)證成功后,下一次請(qǐng)求如何知道是那個(gè)用戶的請(qǐng)求呢?
內(nèi)部原理:1個(gè)請(qǐng)求1個(gè)Subject原理:由于ShiroFilterFactoryBean本質(zhì)是個(gè)AbstractShiroFilter過濾器,所以每次請(qǐng)求都會(huì)執(zhí)行doFilterInternal里面的createSubject方法。
源碼:
shiro內(nèi)置的session
session.setAttribute(“username”,username)就是將username保存到session中,session的key值為username,其信息(value)為username,或者引用值。這樣以后可以通過session.getAttribute(“username”)的方法來獲取這個(gè)對(duì)象。通常,當(dāng)用戶已經(jīng)登錄系統(tǒng)后,就可以在session中存儲(chǔ)一個(gè)用戶信息對(duì)象,伺候可以隨時(shí)從session中將這個(gè)對(duì)象取出來進(jìn)行一些操作,比如身份驗(yàn)證等等。
request.getSession()可以獲得HttpSession類型的對(duì)象,通常稱之為session對(duì)象,session對(duì)象的作用域?yàn)橐淮螘?huì)話,通常瀏覽器不關(guān)閉,保存的值就不會(huì)消失,當(dāng)然也會(huì)出現(xiàn)session超時(shí)。服務(wù)器里面可以設(shè)置session的超時(shí)時(shí)間,web.xml中有一個(gè)session time out的地方,tomcat默認(rèn)為30分鐘。
session. setAttribute(“key”,value)是session設(shè)置值的方法,原理同Map集合。
getAttribute的返回值類型是Object,需要向下轉(zhuǎn)型,轉(zhuǎn)成你的userName類型的。比如,String session1= (String)session.getAttribute(“student”) ;
5.自定義登錄攔截器
這種辦法不需要引入依賴,只需要繼承HandlerInterceptor 即可 實(shí)現(xiàn)非常簡單:
@Slf4j public class UserLoginInterceptor implements HandlerInterceptor {/*** true 表示繼續(xù)流程,false表示中斷* @param request* @param response* @param handler* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info("preHandle...");User user = (User) request.getSession().getAttribute(MallConst.CURRENT_USER);if (user == null) {log.info("user=null");throw new UserLoginException();}return true;} }然后定義一個(gè)配置類,啟動(dòng)時(shí)springboot便能進(jìn)行自動(dòng)配置
@Configuration public class InterceptorConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new UserLoginInterceptor()).addPathPatterns("/**")//自己添加需要攔截的路徑.excludePathPatterns("/error", "/user/login", "/user/register", "/categories", "/products/*");//哪些路徑不需要攔截} }總結(jié)
以上是生活随笔為你收集整理的springboot整合shiro和session的详细过程和自定义登录拦截器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springboot整合websocke
- 下一篇: springboot中使用Applica