Browse Source

shiro调整,优化配置

laowo 3 years ago
parent
commit
6d86350f61

+ 216 - 0
src/main/java/com/usky/config/shiro/ShiroConfig.java

@@ -0,0 +1,216 @@
+/**
+ * MIT License
+ * Copyright (c) 2018 yadong.zhang
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.usky.config.shiro;
+
+import org.apache.shiro.authc.credential.CredentialsMatcher;
+import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
+import org.apache.shiro.mgt.SecurityManager;
+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.apache.shiro.web.session.mgt.DefaultWebSessionManager;
+import org.crazycake.shiro.*;
+import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.DependsOn;
+import org.springframework.core.annotation.Order;
+import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.util.StringUtils;
+import redis.clients.jedis.HostAndPort;
+import redis.clients.jedis.JedisCluster;
+
+import javax.annotation.Resource;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Shiro配置类
+ *
+ * @author yadong.zhang (yadong.zhang0415(a)gmail.com)
+ * @version 1.0
+ * @website https://www.zhyd.me
+ * @date 2018/4/24 14:37
+ * @since 1.0
+ */
+@Configuration
+@Order(-1)
+public class ShiroConfig {
+    @Resource
+    LettuceConnectionFactory lettuceConnectionFactory;
+
+    @Bean
+    public MethodInvokingFactoryBean methodInvokingFactoryBean(@Qualifier("MysecurityManager") DefaultWebSecurityManager securityManager) {
+        MethodInvokingFactoryBean bean = new MethodInvokingFactoryBean();
+        bean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
+        bean.setArguments(securityManager);
+        return bean;
+    }
+
+    @Bean(name = "lifecycleBeanPostProcessor")
+    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
+        return new LifecycleBeanPostProcessor();
+    }
+
+    @Bean(name = "shiroFilter")
+    public ShiroFilterFactoryBean shirFilter(@Qualifier("MysecurityManager") DefaultWebSecurityManager securityManager) {
+        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
+        // 必须设置 SecurityManager
+        shiroFilterFactoryBean.setSecurityManager(securityManager);
+        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
+        //       shiroFilterFactoryBean.setLoginUrl("");
+        // 登录成功后要跳转的链接
+        //  shiroFilterFactoryBean.setSuccessUrl("");
+        // 未授权界面;
+        shiroFilterFactoryBean.setUnauthorizedUrl("/error/403");
+        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
+        filterChainDefinitionMap.put("/doc.html", "anon");
+        filterChainDefinitionMap.put("/sys/login", "anon");
+        filterChainDefinitionMap.put("/**/*.js", "anon");
+        filterChainDefinitionMap.put("/**/*.css", "anon");
+        filterChainDefinitionMap.put("/**/*.html", "anon");
+        filterChainDefinitionMap.put("/**/*.svg", "anon");
+        filterChainDefinitionMap.put("/**/*.pdf", "anon");
+        filterChainDefinitionMap.put("/**/*.jpg", "anon");
+        filterChainDefinitionMap.put("/**/*.png", "anon");
+        filterChainDefinitionMap.put("/**/*.ico", "anon");
+        filterChainDefinitionMap.put("/**/*.ttf", "anon");
+        filterChainDefinitionMap.put("/**/*.woff", "anon");
+        filterChainDefinitionMap.put("/**/*.woff2", "anon");
+        filterChainDefinitionMap.put("/druid/**", "anon");
+        filterChainDefinitionMap.put("/swagger-ui.html", "anon");
+        filterChainDefinitionMap.put("/swagger**/**", "anon");
+        filterChainDefinitionMap.put("/webjars/**", "anon");
+        filterChainDefinitionMap.put("/v2/**", "anon");
+    //    filterChainDefinitionMap.put("/**", "authc");
+        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
+        return shiroFilterFactoryBean;
+    }
+
+    @Bean
+    @DependsOn("lifecycleBeanPostProcessor")
+    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
+        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
+        creator.setProxyTargetClass(true);
+        return creator;
+    }
+
+    @Bean(name = "MysecurityManager")
+    public DefaultWebSecurityManager securityManager(@Qualifier("shiroRealm") ShiroRealm authRealm) {
+        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
+        // 设置realm.
+        securityManager.setRealm(authRealm);
+        securityManager.setCacheManager(redisCacheManager());
+        // 自定义session管理 使用redis
+        securityManager.setSessionManager(sessionManager());
+        return securityManager;
+    }
+
+    @Bean(name = "shiroRealm")
+    public ShiroRealm shiroRealm(@Qualifier("credentialsMatcher") CredentialsMatcher matcher) {
+        ShiroRealm shiroRealm = new ShiroRealm();
+        shiroRealm.setCredentialsMatcher(credentialsMatcher());
+        return shiroRealm;
+    }
+
+    /**
+     * 凭证匹配器
+     */
+    @Bean(name = "credentialsMatcher")
+    public CredentialsMatcher credentialsMatcher() {
+        HashedCredentialsMatcher hashedMatcher = new HashedCredentialsMatcher();
+        hashedMatcher.setHashAlgorithmName("md5");
+//        hashedMatcher.setHashIterations(1);
+        return hashedMatcher;
+    }
+
+    /**
+     * 开启shiro aop注解支持.
+     * 使用代理方式;所以需要开启代码支持;
+     *
+     * @param securityManager
+     * @return
+     */
+    @Bean
+    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
+        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
+        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
+        return authorizationAttributeSourceAdvisor;
+    }
+
+    @Bean
+    public RedisManager redisManager() {
+        RedisManager manager;
+        RedisManager redisManager = new RedisManager();
+        redisManager.setHost(lettuceConnectionFactory.getHostName());
+        redisManager.setPort(lettuceConnectionFactory.getPort());
+        redisManager.setDatabase(1);
+        redisManager.setTimeout(0);
+        if (!StringUtils.isEmpty(lettuceConnectionFactory.getPassword())) {
+            redisManager.setPassword(lettuceConnectionFactory.getPassword());
+        }
+        manager = redisManager;
+
+        return manager;
+    }
+
+
+    /**
+     * cacheManager 缓存 redis实现
+     * 使用的是shiro-redis开源插件
+     *
+     * @return
+     */
+    @Bean
+    public RedisCacheManager redisCacheManager() {
+        RedisCacheManager redisCacheManager = new RedisCacheManager();
+        redisCacheManager.setPrincipalIdFieldName("userId");
+        redisCacheManager.setRedisManager(redisManager());
+        return redisCacheManager;
+    }
+
+    /**
+     * RedisSessionDAO shiro sessionDao层的实现 通过redis
+     * 使用的是shiro-redis开源插件
+     */
+//    @Bean
+    public RedisSessionDAO redisSessionDAO() {
+        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
+        redisSessionDAO.setRedisManager(redisManager());
+        return redisSessionDAO;
+    }
+    /**
+     * shiro session的管理
+     */
+    @Bean
+    public DefaultWebSessionManager sessionManager() {
+        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
+        sessionManager.setGlobalSessionTimeout(2592000 * 1000L);
+        sessionManager.setSessionDAO(redisSessionDAO());
+        return sessionManager;
+    }
+
+}

+ 118 - 0
src/main/java/com/usky/config/shiro/ShiroRealm.java

@@ -0,0 +1,118 @@
+package com.usky.config.shiro;
+
+import com.usky.entity.sys.vo.SysUserVO;
+import com.usky.service.sys.menuService.MenuService;
+import com.usky.service.sys.user.LoginService;
+import com.usky.service.sys.user.UserService;
+import com.usky.utils.ShiroUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.authc.*;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.cache.Cache;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.apache.shiro.util.ByteSource;
+import org.apache.shiro.util.SimpleByteSource;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.Set;
+
+/**
+ * @Description: 用户登录鉴权和获取用户授权
+ * @Author: Scott
+ * @Date: 2019-4-23 8:13
+ * @Version: 1.1
+ */
+@Slf4j
+public class ShiroRealm extends AuthorizingRealm {
+
+    @Resource
+    @Lazy
+    private LoginService loginService;
+    @Resource
+    @Lazy
+    private UserService userService;
+    @Resource
+    @Lazy
+    private MenuService menuService;
+    /**
+     * 权限信息认证(包括角色以及权限)是用户访问controller的时候才进行验证(redis存储的此处权限信息)
+     * 触发检测用户权限时才会调用此方法,例如checkRole,checkPermission
+     * @param principals 身份信息
+     * @return AuthorizationInfo 权限信息
+     */
+    @Override
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
+        SysUserVO user = ShiroUtils.getSysUserVo();
+        // 角色列表
+        Set<String> roles;
+        // 功能列表
+        Set<String> menus;
+        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
+        // 管理员拥有所有权限
+        if (user.isAdmin()) {
+            info.addRole("admin");
+            info.addStringPermission("*:*:*");
+        } else {
+
+            roles = userService.queryRoleKeys(user.getUserId());
+            menus = menuService.qyeryPermsByUserId(user.getUserId());
+            // 角色加入AuthorizationInfo认证对象
+            info.setRoles(roles);
+            // 权限加入AuthorizationInfo认证对象
+            info.setStringPermissions(menus);
+        }
+        return info;
+    }
+
+    /**
+     * 用户信息认证是在用户进行登录的时候进行验证(不存redis)
+     * 也就是说验证用户输入的账号和密码是否正确,错误抛出异常
+     *
+     * @param auth 用户登录的账号密码信息
+     * @return 返回封装了用户信息的 AuthenticationInfo 实例
+     * @throws AuthenticationException
+     */
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
+
+        String username = ((UsernamePasswordToken) auth).getUsername();
+        //获取用户
+        SysUserVO user = loginService.findUserByUsername(username);
+        if (user == null) {
+            return null;
+        } else {
+            //封装AuthenticationInfo
+            ByteSource bsSalt = new SimpleByteSource(user.getSalt());
+            return new SimpleAuthenticationInfo(user, user.getPassword(), bsSalt, getName());
+        }
+    }
+
+
+    /**
+     * 清除当前用户的权限认证缓存
+     *
+     * @param principals 权限信息
+     */
+    @Override
+    public void clearCache(PrincipalCollection principals) {
+        super.clearCache(principals);
+    }
+    /**
+     ////     * 清理所有用户授权信息缓存
+     ////     */
+    public void clearAllCachedAuthorizationInfo()
+    {
+        Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
+        if (cache != null)
+        {
+            for (Object key : cache.keys())
+            {
+                cache.remove(key);
+            }
+        }
+    }
+}