shiro登陆、权限,redisTemplate

 

**************************************** 登陆拦截 ****************************************
登陆过后才不被拦截
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) throws IOException {
        ShiroFilterFactoryBean factory = new ShiroFilterFactoryBean();
        factory.setSecurityManager(securityManager);
        factory.setLoginUrl("/unauthorizedxmh");
        factory.setUnauthorizedUrl("/forbidden");
        Map<String, String> filterMap =  new LinkedHashMap();
//        OrderedProperties properties = new OrderedProperties("classpath:shiro.properties");
//        filterMap.putAll(Maps.fromProperties(properties));
        filterMap.put("/login","anon");
//        filterMap.put("/**","authc,user");
        filterMap.put("/**","authc");
        factory.setFilterChainDefinitionMap(filterMap);
        Map<String, Filter> filters = factory.getFilters();
        filters.put("authc",new UserLoginFilter());
        return factory;
    }

/**
 * 自定义shiro登录过滤器,判断是ajax请求返回json,否则重定向页面
 */
public class UserLoginFilter extends FormAuthenticationFilter {
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        if(!isAjaxRequest(WebUtils.toHttp(request))){
            return super.onAccessDenied(request, response);
        }else{
            HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
            //这里是个坑,如果不设置的接受的访问源,那么前端都会报跨域错误,因为这里还没到corsConfig里面
            httpServletResponse.setHeader("Access-Control-Allow-Origin", ((HttpServletRequest) request).getHeader("Origin"));
            httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setContentType("application/json");

            JSONObject object = new JSONObject();
            object.put("code",400);
            object.put("msg","登录超时,请重新登录");
            object.put("timestamp",System.currentTimeMillis());
            PrintWriter writer = httpServletResponse.getWriter();
            writer.println(object.toJSONString());
            writer.flush();
            writer.close();
            //todo
            return false;
        }
    }

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        if (request instanceof HttpServletRequest) {
            if ("OPTIONS".equals(((HttpServletRequest) request).getMethod().toUpperCase())) {
                return true;
            }
        }
        return super.isAccessAllowed(request, response, mappedValue);
    }
    
    /**
     * 是否是Ajax请求
     *
     * @param request
     * @return
     */
    private static boolean isAjaxRequest(HttpServletRequest request) {
        String requestedWith = request.getHeader("x-requested-with");
        if (requestedWith != null && "XMLHttpRequest".equalsIgnoreCase(requestedWith)) {
            return true;
        } else {
            return false;
        }
    }
}

****************************************  权限拦截 ****************************************
无权访问报异常 org.apache.shiro.authz.UnauthorizedException 
第一种写法
    @RequestMapping("/hello1")
    @ResponseBody
    @RequiresPermissions("xmh.test.permission")//必须先login
    public String hello1() {

        System.out.println("***************hello1");

        return "hello111:";
    }
第二种写法
     boolean b1 = SecurityUtils.getSubject().isPermitted("xxxx");
     boolean b2 = SecurityUtils.getSubject().isPermitted("xmh.test.permission");
     System.out.println(b1+" "+b2);
public class AuthorizeRealm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        principals.getPrimaryPrincipal();
        // 添加用户权限
        info.addStringPermission("xmh.test.permission");
        System.out.println("AuthorizationInfo:!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
        //https://blog.csdn.net/wwwffy/article/details/78188973
        return info;
}
/**
     * 开启shiro aop注解支持,使用代理方式; 所以需要开启代码支持; Controller才能使用@RequiresPermissions
     *
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }

扩展知识
@ControllerAdvice
public class AdviceController { 异常处理函数

  

 

 

 

 

UsernamePasswordToken authenticationToken = new UsernamePasswordToken();
authenticationToken.setUsername(userId);
authenticationToken.setPassword("001".toCharArray());
currentUser.login(authenticationToken);//登录时触发doGetAuthenticationInfo登录校验

@Bean
public AuthorizeRealm authorizeRealm(){
return  new AuthorizeRealm();
}
@Bean
public DefaultWebSecurityManager securityManager(SessionManager sessionManager) {//AuthorizingRealm realm, SessionManager sessionManager
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
manager.setRealm(authorizeRealm());
//        manager.setCacheManager(new RedisCacheManager());
manager.setSessionManager(sessionManager);
return manager;
}
public class AuthorizeRealm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        principals.getPrimaryPrincipal();
        // 添加用户权限
        info.addStringPermission("user");
        System.out.println("AuthorizationInfo:****************");
        //https://blog.csdn.net/wwwffy/article/details/78188973
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)token;
        String userName = usernamePasswordToken.getUsername();
        System.out.println("AuthorizeRealm****************userName:"+userName);

        StringBuilder sb = new StringBuilder(100);
        for (int i = 0; i < usernamePasswordToken.getPassword().length; i++) {
            sb.append(usernamePasswordToken.getPassword()[i]);
        }
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userName, sb.toString(), getName());
        return simpleAuthenticationInfo;
//        return null;//登录失败
    }
}

 

分布式集群,共享session
http://localhost:9990/hello3?userId=1qaz21111
http://localhost:9990/hello1 获取相同userId
http://localhost:9999/hello1 获取相同userId
<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-spring</artifactId>
	<version>1.4.1</version>
</dependency>

    @Autowired
    private RedisTemplate<Serializable, Serializable> redisTemplate;
    @RequestMapping("/hello3")
    @ResponseBody
    public ResultVo hello3(String userId) { 
    ResultVo resultVo = new ResultVo();
        System.out.println("TestController2*****************************:userId:"+userId);
        Subject currentUser = SecurityUtils.getSubject();
        Session session = currentUser.getSession();
        session.setAttribute("userId",userId);
        System.out.println("sessionId:"+session.getId());
        resultVo.setMessage((String)session.getId());
        return resultVo;
    }

    @RequestMapping("/hello1")
    @ResponseBody
    public String hello1() {
        System.out.println("hello1");
        Subject currentUser = SecurityUtils.getSubject();
        Session session = currentUser.getSession();
        String userId = (String) session.getAttribute("userId");
        System.out.println("sessionId:"+session.getId()+",userId:"+userId);
        return "hello:"+session.getId()+","+userId;
    }

1,在创建Subject的时候还没有用户信息,只有当subject.login(token)的时候会获取用户信息,才能将用户信息放入session中
2,Shiro对于ThreadLocal<T>的使用方式是将其封装为对自定义的ThreadContext的调用。关于ThreadContext,其显式绑定的就两个实例:Subject和SecurityManager 。这个观察其定义的bind方法就知晓了
3, 但若是容器不存在session,那么Shiro会提供内置的企业级session来管理。当然在开发中,也可以使⽤SessionDAO允许
数据源持久化Session。  

@Configuration
//@ConditionalOnBean(Realm.class)
public class ShiroConfig {
    @Bean
    public Cookie cookie() {
        SimpleCookie cookie = new SimpleCookie("OTC-SESSIONID");
        cookie.setSecure(false);
        cookie.setHttpOnly(true);
        cookie.setPath("/");
        cookie.setMaxAge(86400);
//        cookie.setMaxAge(-1);
        return cookie;
    }
    @Bean
    public SessionListener sessionListener() {
        return new SessionListener();
    }
    @Bean
    public SessionDAO sessionDao() {//Realm realm
        RedisSessionDAO dao = new RedisSessionDAO();
//        realm.setSessionDAO(dao);//其他模块使用
        return dao;
    }
    @Bean
    public SessionManager sessionManager(SessionDAO sessionDao, SessionListener sessionListener, Cookie cookie) {//
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setGlobalSessionTimeout(86400000L);
        sessionManager.setSessionDAO(sessionDao);
        sessionManager.getSessionListeners().add(sessionListener);
        sessionManager.setSessionIdCookie(cookie);
        return sessionManager;
    }
    @Bean
    public DefaultWebSecurityManager securityManager(SessionManager sessionManager) {//AuthorizingRealm realm, SessionManager sessionManager
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
//        manager.setRealm(realm);
//        manager.setCacheManager(new RedisCacheManager());
        manager.setSessionManager(sessionManager);
        return manager;
    }
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) throws IOException {
        ShiroFilterFactoryBean factory = new ShiroFilterFactoryBean();
        factory.setSecurityManager(securityManager);
//        factory.setLoginUrl("/unauthorized");
//        factory.setUnauthorizedUrl("/forbidden");
//        Map<String, String> filterMap = InstanceUtil.newLinkedHashMap();
//        OrderedProperties properties = new OrderedProperties("classpath:config/shiro.properties");
//        filterMap.putAll(Maps.fromProperties(properties));
//        factory.setFilterChainDefinitionMap(filterMap);
//        Map<String, Filter> filters = factory.getFilters();
//        filters.put("authc",new UserLoginFilter());
        return factory;
    }
}

public class RedisSessionDAO extends AbstractSessionDAO {
    private static final int EXPIRE_TIME = 600;
    @Autowired
    private RedisTemplate<Serializable, Serializable> redisTemplate;
    private final static Logger logger = LogManager.getLogger();
    public void delete(Serializable sessionId) {
        if (sessionId != null) {
            byte[] sessionKey = buildRedisSessionKey(sessionId);
            RedisConnectionFactory factory = redisTemplate.getConnectionFactory();
            RedisConnection conn = null;
            try {
                conn = RedisConnectionUtils.getConnection(factory);
                conn.del(sessionKey);
            } finally {
                RedisConnectionUtils.releaseConnection(conn, factory);
            }
        }
    }
@Override protected Serializable doCreate(Session session) { Serializable sessionId = generateSessionId(session); assignSessionId(session, sessionId); saveSession(session); return sessionId; } @Override protected Session doReadSession(Serializable sessionId) { byte[] sessionKey = buildRedisSessionKey(sessionId); RedisConnectionFactory factory = redisTemplate.getConnectionFactory(); RedisConnection conn = null; try { conn = RedisConnectionUtils.getConnection(factory); byte[] value = conn.get(sessionKey); if (value == null) { return null; } Session session = SerializeUtil.deserialize(value, SimpleSession.class); return session; } finally { RedisConnectionUtils.releaseConnection(conn, factory); } } @Override public void update(Session session) throws UnknownSessionException { saveSession(session); } @Override public void delete(Session session) { if (session != null) { Serializable id = session.getId(); if (id != null) { RedisConnectionFactory factory = redisTemplate.getConnectionFactory(); RedisConnection conn = null; try { conn = RedisConnectionUtils.getConnection(factory); conn.del(buildRedisSessionKey(id)); } finally { RedisConnectionUtils.releaseConnection(conn, factory); } } } } @Override public Collection<Session> getActiveSessions() { // List<Session> list = InstanceUtil.newArrayList(); List<Session> list = new ArrayList<>(); RedisConnectionFactory factory = redisTemplate.getConnectionFactory(); RedisConnection conn = null; try { conn = RedisConnectionUtils.getConnection(factory); Set<byte[]> set = conn.keys((Constants.REDIS_SHIRO_SESSION + "*").getBytes()); for (byte[] key : set) { list.add(SerializeUtil.deserialize(conn.get(key), SimpleSession.class)); } } finally { RedisConnectionUtils.releaseConnection(conn, factory); } return list; } private void saveSession(Session session) { if (session == null || session.getId() == null) { throw new UnknownSessionException("session is empty"); } byte[] sessionKey = buildRedisSessionKey(session.getId()); // int sessionTimeOut = PropertiesUtil.getInt("session.maxInactiveInterval", getExpireTime()); int sessionTimeOut =86400; byte[] value = SerializeUtil.serialize(session); RedisConnectionFactory factory = redisTemplate.getConnectionFactory(); RedisConnection conn = null; try { conn = RedisConnectionUtils.getConnection(factory); conn.set(sessionKey, value, Expiration.seconds(sessionTimeOut), SetOption.UPSERT); } finally { RedisConnectionUtils.releaseConnection(conn, factory); } } protected int getExpireTime() { return EXPIRE_TIME; } private byte[] buildRedisSessionKey(Serializable sessionId) { return (Constants.REDIS_SHIRO_SESSION + sessionId).getBytes(); } } public class SessionListener implements org.apache.shiro.session.SessionListener { private Logger logger = LogManager.getLogger(); @Autowired RedisTemplate redisTemplate; /* (non-Javadoc) * @see org.apache.shiro.session.SessionListener#onStart(org.apache.shiro.session.Session) */ @Override public void onStart(Session session) { session.setAttribute(Constants.WEBTHEME, "default"); logger.info("创建了一个Session连接:[" + session.getId() + "]"); redisTemplate.opsForSet().add(Constants.ALLUSER_NUMBER, session.getId()); } /* (non-Javadoc) * @see org.apache.shiro.session.SessionListener#onStop(org.apache.shiro.session.Session) */ @Override public void onStop(Session session) { if (getAllUserNumber() > 0) { logger.info("销毁了一个Session连接:[" + session.getId() + "]"); } session.removeAttribute(Constants.CURRENT_USER); redisTemplate.opsForSet().remove(Constants.ALLUSER_NUMBER, session.getId()); } /* (non-Javadoc) * @see org.apache.shiro.session.SessionListener#onExpiration(org.apache.shiro.session.Session) */ @Override public void onExpiration(Session session) { onStop(session); } /** 获取在线用户数量 */ public Integer getAllUserNumber() { return redisTemplate.opsForSet().size(Constants.ALLUSER_NUMBER).intValue(); } } @Configuration public class RedisConfig { // @Bean // public GenericObjectPoolConfig redisPoolConfig() { // GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); // poolConfig.setMinIdle(PropertiesUtil.getInt("redis.minIdle")); // poolConfig.setMaxIdle(PropertiesUtil.getInt("redis.maxIdle")); // poolConfig.setMaxTotal(PropertiesUtil.getInt("redis.maxTotal")); // poolConfig.setMaxWaitMillis(PropertiesUtil.getInt("redis.maxWaitMillis")); // return poolConfig; // } // // @Bean(destroyMethod = "shutdown") // @ConditionalOnMissingBean(ClientResources.class) // public ClientResources clientResources() { // return DefaultClientResources.create(); // } /** * 连接redis的工厂类 * * @return */ @Bean(name = "redisConnectionFactory") public RedisConnectionFactory redisConnectionFactory() {//GenericObjectPoolConfig redisPoolConfig, ClientResources clientResources LettuceConnectionFactory connectionFactory; // String nodes = PropertiesUtil.getString("spring.redis.cluster.nodes"); // String master = PropertiesUtil.getString("redis.master"); // String sentinels = PropertiesUtil.getString("redis.sentinels"); // Duration commandTimeout = Duration.ofMillis(PropertiesUtil.getInt("redis.commandTimeout", 60000)); // Duration shutdownTimeout = Duration.ofMillis(PropertiesUtil.getInt("redis.shutdownTimeout", 5000)); // LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder builder = LettucePoolingClientConfiguration.builder() // .poolConfig(redisPoolConfig).commandTimeout(commandTimeout).shutdownTimeout(shutdownTimeout) // .clientResources(clientResources); // LettuceClientConfiguration clientConfiguration = builder.build(); RedisPassword password = RedisPassword.of("123"); // String host = PropertiesUtil.getString("redis.host", "localhost"); // Integer port = PropertiesUtil.getInt("redis.port", 6379); // Integer database = PropertiesUtil.getInt("redis.database", 0); // if (DataUtil.isNotEmpty(nodes)) { // List<String> list = InstanceUtil.newArrayList(nodes.split(",")); // RedisClusterConfiguration configuration = new RedisClusterConfiguration(list); // configuration.setMaxRedirects(PropertiesUtil.getInt("redis.cluster.max-redirects")); // configuration.setPassword(password); // connectionFactory = new LettuceConnectionFactory(configuration, clientConfiguration); // } else if (DataUtil.isNotEmpty(master) && DataUtil.isNotEmpty(sentinels)) { // Set<String> set = InstanceUtil.newHashSet(sentinels.split(",")); // RedisSentinelConfiguration configuration = new RedisSentinelConfiguration(master, set); // configuration.setPassword(password); // connectionFactory = new LettuceConnectionFactory(configuration, clientConfiguration); // } else { RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(); configuration.setPassword(password); configuration.setHostName("192.168.89.128"); configuration.setPort(6379); configuration.setDatabase(0); connectionFactory = new LettuceConnectionFactory(configuration); AbstractRedisClient s; // } return connectionFactory; } @Bean(name = "redisTemplate") public RedisTemplate<Serializable, Serializable> redisTemplate() {//<String, Object> //StringRedisTemplate的构造方法中默认设置了stringSerializer RedisTemplate<Serializable, Serializable> template = new RedisTemplate<>(); //设置开启事务 template.setEnableTransactionSupport(true); //set key serializer StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer(); GenericFastJsonRedisSerializer valueSerializer = new GenericFastJsonRedisSerializer(); template.setKeySerializer(stringRedisSerializer); template.setValueSerializer(valueSerializer); template.setConnectionFactory(redisConnectionFactory()); template.afterPropertiesSet(); return template; } } public final class SerializeUtil { private SerializeUtil() { } private static final Logger logger = LogManager.getLogger(); /** * 序列化 * * @param object * @return */ public static final byte[] serialize(Object object) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = null; try { oos = new ObjectOutputStream(baos); oos.writeObject(object); return baos.toByteArray(); } catch (IOException ex) { throw new RuntimeException(ex.getMessage(), ex); } finally { try { if (oos != null) { oos.close(); } } catch (Exception e) { logger.error("", e); } try { if (baos != null) { baos.close(); } } catch (Exception e) { logger.error("", e); } } } /** * 反序列化 * * @param bytes * @return */ public static final Object deserialize(byte[] bytes) { return deserialize(bytes, Object.class); } /** * 反序列化 * * @param bytes * @return */ @SuppressWarnings("unchecked") public static final <K> K deserialize(byte[] bytes, Class<K> cls) { ByteArrayInputStream bais = new ByteArrayInputStream(bytes); ObjectInputStream ois = null; try { ois = new ObjectInputStream(bais); return (K)ois.readObject(); } catch (IOException ex) { throw new RuntimeException(ex.getMessage(), ex); } catch (ClassNotFoundException ex) { throw new RuntimeException(ex.getMessage(), ex); } finally { try { if (ois != null) { ois.close(); } } catch (Exception e) { logger.error("", e); } try { if (bais != null) { bais.close(); } } catch (Exception e) { logger.error("", e); } } } }

  

 

posted @ 2022-06-17 21:26  XUMT111  阅读(41)  评论(0编辑  收藏  举报