Shiro在线刷新权限
生活随笔
收集整理的這篇文章主要介紹了
Shiro在线刷新权限
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
shiro-spring-boot-web-starter 1.6.0版本[SpringBoot微服務框架]
提前說好,說我缺文件的,一般那是不中要的
ShiroFreshService
/*** 初始化權限 -> 拿全部權限** @param :* @return: java.util.Map<java.lang.String, java.lang.String>*/Map<String, String> loadFilterChainDefinitionMap();/*** 重新構建權限過濾器* 一般在修改了用戶角色、用戶等信息時,需要再次調用該方法*/void reCreateFilterChains(ShiroFilterFactoryBean shiroFilterFactoryBean);ShiroFreshServiceImpl
@Slf4j @Service public class ShiroFreshServiceImpl implements ShiroFreshService {@Autowiredprivate RoleMenuService roleMenuService;@Autowiredprivate ConfigProperties configProperties;private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();private static Lock writeLock = readWriteLock.writeLock();@Overridepublic Map<String, String> loadFilterChainDefinitionMap() {Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();filterChainDefinitionMap.put("/validcaptcha", "anon");//驗證驗證碼filterChainDefinitionMap.put("/validate", "anon");filterChainDefinitionMap.put("/login", "anon");filterChainDefinitionMap.put("/logout", "anon");filterChainDefinitionMap.put("/css/** ", "anon");filterChainDefinitionMap.put("/image/**", "anon");filterChainDefinitionMap.put("/js/**", "anon");filterChainDefinitionMap.put("/error/**", "anon");filterChainDefinitionMap.put("/plugins/**", "anon");filterChainDefinitionMap.put("/favicon.ico", "anon");filterChainDefinitionMap.put("/401", "anon");filterChainDefinitionMap.put("/403", "anon");filterChainDefinitionMap.put("/404", "anon");filterChainDefinitionMap.put("/500", "anon");List<UrlRoleVo> urlRoleVoList = roleMenuService.findAllUrlRolesList();String roleCode = configProperties.getAdminRoleCode();if (CollectionUtils.isNotEmpty(urlRoleVoList)) {urlRoleVoList.forEach(ur -> filterChainDefinitionMap.put(ur.url(), "roles[" + ur.role().toUpperCase() + "," + roleCode + "]"));}//對所有用戶認證filterChainDefinitionMap.put("/**", "authc");return filterChainDefinitionMap;}@Overridepublic void reCreateFilterChains(ShiroFilterFactoryBean shiroFilterFactoryBean) {writeLock.lock();try {AbstractShiroFilter shiroFilter = null;try {shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();} catch (Exception e) {log.error("ShiroFreshServiceImpl刷新權限異常", e);throw new HdapException(GET_SHIRO_FILTER);}PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter.getFilterChainResolver();DefaultFilterChainManager filterChainManager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();//加載數據Map<String, String> filterChainDefinitionMap = loadFilterChainDefinitionMap();// 清空老的權限控制filterChainManager.getFilterChains().clear();shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);// 重新構建生成for (Map.Entry<String, String> filterChainDefinition : filterChainDefinitionMap.entrySet()) {filterChainManager.createChain(filterChainDefinition.getKey(), filterChainDefinition.getValue());}} finally {writeLock.unlock();}} }Config
/*** 參考【僅作參考】* 1. https://blog.csdn.net/New_Yao/article/details/100769385* 2. https://www.cnblogs.com/zhengqing/p/11603824.html* *.https://shiro.apache.org/spring-boot.html*/ @Slf4j @Configuration public class SysUserSecurityConfig {@Value("${server.servlet.session.timeout}")@DurationUnit(ChronoUnit.SECONDS)private Duration timeout = Duration.ofMinutes(30L);@Autowiredprivate ShiroFreshService shiroFreshService;/*** 設置用于匹配密碼的CredentialsMatcher* SHA-256** @return*/@Beanpublic HashedCredentialsMatcher credentialsMatcher() {HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();// 散列算法,這里使用更安全的sha256算法credentialsMatcher.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME);// 散列迭代次數credentialsMatcher.setHashIterations(1024);return credentialsMatcher;}/*** 配置自定義Realm** @return*/@Beanpublic SysUserRealm sysUserRealm() {SysUserRealm sysUserRealm = new SysUserRealm();// 配置使用哈希密碼匹配sysUserRealm.setCredentialsMatcher(credentialsMatcher());// 啟用身份驗證緩存,即緩存AuthenticationInfo信息,默認falsesysUserRealm.setAuthenticationCachingEnabled(true);// 啟用授權緩存,即緩存AuthorizationInfo信息,默認false,一旦配置了緩存管理器,授權緩存默認開啟sysUserRealm.setAuthorizationCachingEnabled(true);return sysUserRealm;}/*** 內存中的緩存管理器** @return*/@Beanprotected CacheManager cacheManager() {return new MemoryConstrainedCacheManager();}/*** 配置會話管理器,設定會話超時及保存** @return*/@Bean("sessionManager")public SessionManager sessionManager() {DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();//全局會話超時時間(單位毫秒),默認30分鐘sessionManager.setGlobalSessionTimeout(timeout.getSeconds() * 1000);//是否開啟刪除無效的session對象 默認為truesessionManager.setDeleteInvalidSessions(true);//是否開啟定時調度器進行檢測過期session 默認為truesessionManager.setSessionValidationSchedulerEnabled(true);//設置session失效的掃描時間, 清理用戶直接關閉瀏覽器造成的孤立會話 默認為 1個小時//設置該屬性 就不需要設置 ExecutorServiceSessionValidationScheduler 底層也是默認自動調用ExecutorServiceSessionValidationScheduler//暫時設置為 5秒 用來測試// sessionManager.setSessionValidationInterval(5000);//禁用URL會話重寫sessionManager.setSessionIdUrlRewritingEnabled(false);return sessionManager;}/*** 安全控制中心** @return*/@Bean("securityManager")public SessionsSecurityManager securityManager() {DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();//配置自定義RealmdefaultSecurityManager.setRealm(sysUserRealm());//內存中的緩存管理器defaultSecurityManager.setCacheManager(cacheManager());//配置會話管理器,設定會話超時及保存defaultSecurityManager.setSessionManager(sessionManager());return defaultSecurityManager;}/*** 配置Filter過濾器** @return*/@Beanpublic ShiroFilterFactoryBean shiroFilterFactoryBean() {ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();// 必須設置SecuritManagerfilterFactoryBean.setSecurityManager(securityManager());//用戶未登錄時跳轉的請求路徑filterFactoryBean.setLoginUrl(SysRoute.REDIRECT_LOGIN);//用戶未登錄成功跳轉的請求路徑filterFactoryBean.setSuccessUrl("/");//用戶沒有訪問權限時跳轉的請求路徑filterFactoryBean.setUnauthorizedUrl("/401");Map<String, Filter> filters = new LinkedHashMap();//配置攔截器,實現無權限返回(過濾器制定)filters.put("authc", new MyFormAuthenticationFilter());filters.put("roles", new MyRolesAuthorizationFilter());filterFactoryBean.setFilters(filters);Map<String, String> filterChainDefinitionMap = shiroFreshService.loadFilterChainDefinitionMap();filterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);return filterFactoryBean;}}realm
@Slf4j public class SysUserRealm extends AuthorizingRealm {@Autowiredprivate UserService userService;@Autowiredprivate EmpService empService;@Autowiredprivate ConfigProperties configProperties;/*** 認證*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {String username = (String) authenticationToken.getPrincipal();log.info("#SHIRO#認證" + username);SysUser sysUser = userService.getSysUserOneByUsername(username);if (ObjectUtils.isNotEmpty(sysUser)) {//status 用戶狀態,0,離職,1:正常,2:禁用switch (sysUser.status()) {case 0:throw new UserStatusException(new ErrCode(10001, "用戶離職狀態,禁止登錄"));case 2:throw new UserStatusException(new ErrCode(10002, "用戶鎖定狀態,禁止登錄"));default:break;}return new SimpleAuthenticationInfo(username, sysUser.password(), ByteSource.Util.bytes(username), getName());}throw new UnknownAccountException("用戶名或密碼不存在");}/*** 授權信息*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {log.info("#SHIRO#授權");if (principalCollection == null) {throw new AuthorizationException("用戶憑證不能為空");}SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();String username = (String) getAvailablePrincipal(principalCollection);//登錄用戶角色Set<String> roles = new HashSet<>();List<String> roleCodeList = empService.getRoleCodeListByUsername(username);if (CollectionUtils.isNotEmpty(roleCodeList)) {roles.addAll(roleCodeList.stream().map(String::toUpperCase).collect(Collectors.toSet()));}SysUser sysUser = userService.getSysUserOneByUsername(username);if (ObjectUtils.isNotEmpty(sysUser) && configProperties.getAdminId().equals(sysUser.id())) {roles.add(configProperties.getAdminRoleCode());}info.setRoles(roles);return info;}/*** 自定義方法:清除所有 授權緩存*/public void clearAllCachedAuthorizationInfo() {getAuthorizationCache().clear();}}MyFormAuthenticationFilter
/*** Name: 需要登錄認證* Description:* User: bambo* Date: 2020-07-16* Time: 16:12*/ @Slf4j public class MyFormAuthenticationFilter extends FormAuthenticationFilter {/*** @param request* @param response* @return true-繼續往下執行,false-該filter過濾器已經處理,不繼續執行其他過濾器* @throws IOException*/@Overrideprotected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {log.info("#SHIRO#認證處理(1),onAccessDenied:MyFormAuthenticationFilter");Subject subject = this.getSubject(request, response);if (subject.getPrincipal() == null) {log.info("#SHIRO#認證處理(2-1),憑證丟失【重新登錄】:MyFormAuthenticationFilter");if (AjaxBoolUtil.isAjax((HttpServletRequest) request)) {response.setCharacterEncoding(AjaxBoolUtil.CHARACTER_ENCODING);response.setContentType(AjaxBoolUtil.CONTENT_TYPE);response.getWriter().write(GsonUtil.toString(Result.right("請重新登錄!")));} else {((HttpServletResponse) response).sendRedirect(SysRoute.LOGIN_LOGIN);}} else {log.info("#SHIRO#認證處理(2-2),未經認證【401】:MyFormAuthenticationFilter");if (AjaxBoolUtil.isAjax((HttpServletRequest) request)) {response.setCharacterEncoding(AjaxBoolUtil.CHARACTER_ENCODING);response.setContentType(AjaxBoolUtil.CONTENT_TYPE);response.getWriter().write(GsonUtil.toString(Result.right("未經認證!")));} else {WebUtils.toHttp(response).sendError(401);}}return false;}}MyRolesAuthorizationFilter
@Slf4j public class MyRolesAuthorizationFilter extends AuthorizationFilter {@Overridepublic boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)throws IOException {log.info("#SHIRO#授權效驗(1):MyRolesAuthorizationFilter");final Subject subject = getSubject(request, response);if (subject.getPrincipal() == null) {return false;}final String[] rolesArray = (String[]) mappedValue;if (rolesArray == null || rolesArray.length == 0) {log.info("#SHIRO#(2-1),無指定角色時,無需檢查,允許訪問:MyRolesAuthorizationFilter");return true;}for (String roleName : rolesArray) {if (subject.hasRole(roleName)) {log.info("#SHIRO#(2-2),有匹配角色,允許訪問:MyRolesAuthorizationFilter");return true;}}log.info("#SHIRO#未經授權(3),無授權:MyRolesAuthorizationFilter");return false;}@Overridepublic boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {log.info("#SHIRO#授權處理(1),onAccessDenied:MyRolesAuthorizationFilter");Subject subject = this.getSubject(request, response);if (subject.getPrincipal() == null) {log.info("#SHIRO#授權處理(2-1),憑證丟失【重新登錄】:MyRolesAuthorizationFilter");if (AjaxBoolUtil.isAjax((HttpServletRequest) request)) {response.setCharacterEncoding(AjaxBoolUtil.CHARACTER_ENCODING);response.setContentType(AjaxBoolUtil.CONTENT_TYPE);response.getWriter().write(GsonUtil.toString(Result.right("請重新登錄!")));} else {((HttpServletResponse) response).sendRedirect(SysRoute.LOGIN_LOGIN);}} else {log.info("#SHIRO#授權處理(2-2),未經授權【403】:MyRolesAuthorizationFilter");if (AjaxBoolUtil.isAjax((HttpServletRequest) request)) {response.setCharacterEncoding(AjaxBoolUtil.CHARACTER_ENCODING);response.setContentType(AjaxBoolUtil.CONTENT_TYPE);response.getWriter().write(GsonUtil.toString(Result.right("未經授權!")));} else {WebUtils.toHttp(response).sendError(403);}}return false;} }Sha256PasswordHelper
public class Sha256PasswordHelper {public static String encryption(String username, String pwd) {return new Sha256Hash(pwd, username, 1024).toString();} }ShiroBeanLifecycleConfig
@Configuration public class ShiroBeanLifecycleConfig {/*** 安全框架shiro的bean生命周期* LifecycleBeanPostProcessor將Initializable和Destroyable的實現類統一在其內部自動分別調用了Initializable.init()和Destroyable.destroy()方法,* 從而達到管理shiro bean生命周期的目的。** @return*/@Bean("lifecycleBeanPostProcessor")public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {return new LifecycleBeanPostProcessor();}/*** APC 自動代理創建器* 掃描上下文,尋找所有的Advistor(通知器),將這些Advisor應用到所有符合切入點的Bean中。所以必須在lifecycleBeanPostProcessor創建之后創建。** @return* @DependsOn({"lifecycleBeanPostProcessor"}) 保證創建DefaultAdvisorAutoProxyCreator 之前先創建LifecycleBeanPostProcessor 。*/@Bean@DependsOn({"lifecycleBeanPostProcessor"})public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();//使用cglib方式為Action對象創建代理對象[pom.xml如果引入了aop-starter依賴包裝,就需要做出更改]advisorAutoProxyCreator.setProxyTargetClass(true);return advisorAutoProxyCreator;} }ToolDateUtil
@Slf4j public class ToolDateUtil {//LocalDate -> Datepublic static Date asDate(LocalDate localDate) {return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());}//LocalDateTime -> Datepublic static Date asDate(LocalDateTime localDateTime) {return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());}//String -> Datepublic static Date asYMDDate(String date) {DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");try {return fmt.parse(date);} catch (ParseException e) {log.error(e.getMessage(), e);return null;}}//Date -> LocalDatepublic static LocalDate asLocalDate(Date date) {return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();}//Date -> LocalDateTimepublic static LocalDateTime asLocalDateTime(Date date) {return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();}//Date -> Stringpublic static String YmdHmToString(Date date) {SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm");return formatter.format(date);}//Date -> Stringpublic static String YmdToString(Date date) {SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");return formatter.format(date);}//String -> Datepublic static Date asMinDate(String ymd) {DateTimeFormatter dtfYMD = DateTimeFormatter.ofPattern("yyyy-MM-dd");LocalDate date = LocalDate.parse(ymd, dtfYMD);return asDate(LocalDateTime.of(date, LocalTime.MIN));}//String -> Datepublic static Date asMaxDate(String ymd) {DateTimeFormatter dtfYMD = DateTimeFormatter.ofPattern("yyyy-MM-dd");LocalDate date = LocalDate.parse(ymd, dtfYMD);return asDate(LocalDateTime.of(date, LocalTime.MAX));}}調用
@Autowiredprivate ShiroFilterFactoryBean shiroFilterFactoryBean;shiroFreshService..reCreateFilterChains(shiroFilterFactoryBean)總結
以上是生活随笔為你收集整理的Shiro在线刷新权限的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python基于OpenCV的土壤裂缝分
- 下一篇: 一篇政治经济学论文