springboot整合shiro和session的详细过程和自定义登录拦截器
文章目錄
- 1.shiro依賴
- 2.shiro配置
- shiro過濾器配置:
- 關聯(lián)自定義的其他管理器
- 自定義會話工廠:
- 3.登陸時記錄用戶信息
- 4.shiro一些工具類的學習
- 5.自定義登錄攔截器
shiro是一個安全框架,用于認證和授權,我覺得與springsecurity相比它上手更容易,同時如果是簡單的登錄攔截也可以用登錄攔截器實現,下面先進行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 的職責是驗證用戶帳號,是ShiroAPI 中身份驗證核心的入口點:如果驗證成功,將返回AuthenticationInfo驗證信息;此信息中包含了身份及憑證;如果驗證失敗將拋出相應的AuthenticationException異常
?SecurityManager接口繼承了Authenticator,另外還有一個ModularRealmAuthenticator實現,其委托給多個Realm 進行驗證,驗證規(guī)則通過AuthenticationStrategy接口指定
哪些url是需要攔截的,哪些是不需要攔截的,登錄頁面、登錄成功頁面的url、自定義的Realm等這些信息需要設置到Shiro中
shiro過濾器配置:
/*** Shiro過濾器配置*/@Beanpublic ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();// Shiro的核心安全接口,這個屬性是必須的shiroFilterFactoryBean.setSecurityManager(securityManager);// 身份認證失敗,則跳轉到登錄頁面的配置shiroFilterFactoryBean.setLoginUrl(loginUrl);// 權限認證失敗,則跳轉到指定頁面shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl);// Shiro連接約束配置,即過濾鏈的定義LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();// 對靜態(tài)資源設置匿名訪問filterChainDefinitionMap.put("/favicon.ico**", "anon");//加入自己的路徑和訪問權限// 系統(tǒng)權限列表// 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());// 注銷成功,則跳轉到指定頁面filters.put("logout", logoutFilter());shiroFilterFactoryBean.setFilters(filters);// 所有請求需要認證filterChainDefinitionMap.put("/**", "user,kickout,onlineSession,syncOnlineSession");shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);return shiroFilterFactoryBean;}安全管理器關聯(lián)自己的Realm
@Bean(name="security")public DefaultWebSecurityManager getDefaultManager(@Qualifier("realm")UserRealm userRealm){DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();//關聯(lián)自己的realmdefaultSecurityManager.setRealm(userRealm);return defaultSecurityManager;}@Bean(name = "realm")//創(chuàng)建realm對象public UserRealm userRealm(){return new UserRealm();}關聯(lián)自定義的其他管理器
@Beanpublic SecurityManager securityManager(UserRealm userRealm){DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();// 設置realm.securityManager.setRealm(userRealm);// 記住我securityManager.setRememberMeManager(rememberMe ? rememberMeManager() : null);// 注入緩存管理器;securityManager.setCacheManager(getEhCacheManager());// session管理器securityManager.setSessionManager(sessionManager());return securityManager;}/*** 緩存管理器 使用Ehcache實現*/@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內部相應的組件(DefaultSecurityManager)會自動檢測相應的對象(如Realm)是否實現了CacheManagerAware并自動注入相應的CacheManager。
Shiro提供了CachingRealm,其實現了CacheManagerAware接口,提供了緩存的一些基礎實現;
?AuthenticatingRealm及AuthorizingRealm也分別提供了對AuthenticationInfo和AuthorizationInfo信息的緩存。
Session 緩存
?如SecurityManager實現了SessionSecurityManager,其會判斷SessionManager是否實現了CacheManagerAware接口,如果實現了會把CacheManager設置給它。
?SessionManager也會判斷相應的SessionDAO(如繼承自CachingSessionDAO)是否實現了CacheManagerAware,如果實現了會把CacheManager設置給它
?設置了緩存的SessionManager,查詢時會先查緩存,如果找不到才查數據庫。
自定義會話工廠:
//自定義sessionFactory會話 @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.登陸時記錄用戶信息
在控制器層:
@ApiOperation(value="登錄") @PostMapping("/login")public ResponseResult<User> toLogin(@ApiParam(name="用戶對象",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一些工具類的學習
SecurityUtils.getSubject()是每個請求創(chuàng)建一個Subject, 并保存到ThreadContext的resources(ThreadLocal<Map<Object, Object>>)變量中,也就是一個http請求一個subject,并綁定到當前線程。
subject.login()登陸認證成功后,下一次請求如何知道是那個用戶的請求呢?
內部原理:1個請求1個Subject原理:由于ShiroFilterFactoryBean本質是個AbstractShiroFilter過濾器,所以每次請求都會執(zhí)行doFilterInternal里面的createSubject方法。
源碼:
shiro內置的session
session.setAttribute(“username”,username)就是將username保存到session中,session的key值為username,其信息(value)為username,或者引用值。這樣以后可以通過session.getAttribute(“username”)的方法來獲取這個對象。通常,當用戶已經登錄系統(tǒng)后,就可以在session中存儲一個用戶信息對象,伺候可以隨時從session中將這個對象取出來進行一些操作,比如身份驗證等等。
request.getSession()可以獲得HttpSession類型的對象,通常稱之為session對象,session對象的作用域為一次會話,通常瀏覽器不關閉,保存的值就不會消失,當然也會出現session超時。服務器里面可以設置session的超時時間,web.xml中有一個session time out的地方,tomcat默認為30分鐘。
session. setAttribute(“key”,value)是session設置值的方法,原理同Map集合。
getAttribute的返回值類型是Object,需要向下轉型,轉成你的userName類型的。比如,String session1= (String)session.getAttribute(“student”) ;
5.自定義登錄攔截器
這種辦法不需要引入依賴,只需要繼承HandlerInterceptor 即可 實現非常簡單:
@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;} }然后定義一個配置類,啟動時springboot便能進行自動配置
@Configuration public class InterceptorConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new UserLoginInterceptor()).addPathPatterns("/**")//自己添加需要攔截的路徑.excludePathPatterns("/error", "/user/login", "/user/register", "/categories", "/products/*");//哪些路徑不需要攔截} }總結
以上是生活随笔為你收集整理的springboot整合shiro和session的详细过程和自定义登录拦截器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springboot整合websocke
- 下一篇: springboot中使用Applica