权限框架——shiro的使用看这篇就够了(进阶篇)

关于shiro的学习推荐官网:

在这里插入图片描述
官网链接地址: http://shiro.apache.org/

关于shiro的一些简单配置,如何整合springboot快速启动,快速使用请看上篇文章
地址:https://blog.csdn.net/weixin_42083036/article/details/105701439

本篇文章旨在,提高shiro的性能,用户体验,以及增加shiro的适用范围

1、提高性能篇

1、Redis整合Cachemanager
  • 使用原因:上一篇讲到每一次鉴权,shiro都需要查询一次数据库,对应频繁的接口访问与sql查询,性能和响应速度都极度下降所以我们需要使用缓存。
  • 步骤
    1、加依赖
<!-- shiro+redis缓存插件 -->
     <dependency>
			<groupId>org.crazycake</groupId>
			<artifactId>shiro-redis</artifactId>
			<version>3.1.0</version>
		</dependency>

        2、 配置bean

 	//使用自定义的cacheManager   绑定securityManager
   securityManager.setCacheManager(cacheManager());
  /**
     * 配置redisManager
     *
     */
    public RedisManager getRedisManager(){
        RedisManager redisManager = new RedisManager();
        redisManager.setHost("localhost");
        redisManager.setPort(6379);
        return redisManager;
    }


    /**
     * 配置具体cache实现类
     * @return
     */
    public RedisCacheManager cacheManager(){
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(getRedisManager());
         //设置过期时间,单位是秒,20s,
        redisCacheManager.setExpire(20);

        return redisCacheManager;
    }

        3、安装Redis(已安装的可以忽略)

注:出现问题

class java.lang.String must has getter for field: authCacheKey or id\nWe need a field to identify this Cache Object in Redis. So you need to defined an id field which you can get unique id to identify this principal. For example, if you use UserInfo as Principal class, the id field maybe userId, userName, email, etc. For example, getUserId(), getUserName(), getEmail(), etc.\nDefault value is authCacheKey or id, that means your principal object has a method called \"getAuthCacheKey()\" or \"getId()\""

原因:原先自定义授权返回获取的是用户名称(String)类型,当你绑定了缓存,返回类型变成了对象,造成原因是由于缓存需要一个唯一键作为缓存索引,所以默认返回了对象。

解决方案:修改自定义realm

doGetAuthorizationInfo 方法
原有:
	String username = (String)principals.getPrimaryPrincipal();
	User user = userService.findAllUserInfoByUsername(username);

改为

	User newUser = (User)principals.getPrimaryPrincipal();
    User user = userService.findAllUserInfoByUsername(newUser.getUsername());

doGetAuthenticationInfo方法
原有:
return new SimpleAuthenticationInfo(username, user.getPassword(), this.getClass().getName());

改为
return new SimpleAuthenticationInfo(user, user.getPassword(), this.getClass().getName());

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

此时你会发现除了第一次访问控制台打印了用户信息,说明进行了sql查询,第二次以后访问控制台没有打印相关信息说明没有进行sql查询,直接走的缓存查询相关信息。

2、Redis整合SessionManager
1、为什么?
  • 重启应用,用户无感觉,不影响用户使用
  • 解决多节点sessionid无法共用问题

步骤:

  • 创建自定义持久化session
/**
 * 自定义session持久化
 * @return
 */
public RedisSessionDAO redisSessionDAO(){
    RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
    redisSessionDAO.setRedisManager(getRedisManager());
    //设置持久化超时时间  默认和下面这句话时间设置一样  
    // customSessionManager.setGlobalSessionTimeout(200000);

    return redisSessionDAO;
}
  • 绑定SessionManager
//设置自定义session持久化
customSessionManager.setSessionDAO(redisSessionDAO());

中途可能会报错,如下:

2020-04-29 15:05:40.541 ERROR 11376 --- [nio-8088-exec-2] org.crazycake.shiro.RedisSessionDAO      : serialize session error. session id=boyuan104f486347614bf4b704079c3e53bbdd

很明显是由于实体没有实现序列化接口Serializable导致的。
注:需要把所有相关联的实体全部序列化,否则还是会报错。

  • 缓存id过期时间的设置
设置一个过期时间
 redisSessionDAO.setExpire(180000);

不设置默认和sessionmanager设置时间一致
在这里插入图片描述

3、shiroConfig 常用bean类配置
1、管理生命周期的
  • LifecycleBeanPostProcessor :管理shiro一些bean的生命周期 即bean初始化 与销毁
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
	return new LifecycleBeanPostProcessor();
}
2、开启shiro注解使用的
  • AuthorizationAttributeSourceAdvisor:加入注解的使用,不加入这个AOP注解不生效(shiro的注解 例如 @RequiresGuest)
@Bean
 public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
  AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
}
3、扫描所有的Advistor(通知器)的
  • DefaultAdvisorAutoProxyCreator: 用来扫描上下文寻找所有的Advistor(通知器), 将符合条件的Advisor应用到切入点的Bean中,需要在LifecycleBeanPostProcessor创建后才可以创建
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public  DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setUsePrefix(true);
        return defaultAdvisorAutoProxyCreator;
}

注:因为这个类是扫描所有的bean的,需要被生命周期管理类所管理,必须在生命周期类生成后再注入。所以需要使用@DependsOn(“lifecycleBeanPostProcessor”)

4、shiro自定义sessionid

Shiro 默认的sessionid生成 类名 SessionIdGenerator
创建一个类,实现 SessionIdGenerator 接口的方法

/**
 * 自定义session持久化
 * @return
 */
public RedisSessionDAO redisSessionDAO(){
    RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
    redisSessionDAO.setRedisManager(getRedisManager());

    //设置sessionid生成器
    redisSessionDAO.setSessionIdGenerator(new CustomSessionIdGenerator());

    return redisSessionDAO;
}

总结

分布式应用下的鉴权方式

1、演进方式
  • 单体应用——>多节点
    session——>分布式session(在每个服务都保存一个sessionid)
    好处维护简单
    缺点:资源占用严重,容易造成混乱

  • 分布式应用——>轻量(访问量<10W)
    UUID 使用UUID生产token保存在缓存中
    好处:较传统模式鉴权,服务器的资源占用更少,实现简单
    缺点:由于比较简易,无法处理复杂的鉴权业务,只能用于访问量<10w的项目

  • 微服务

  • JWT(json web token)
    JWT 自定义加密签名等等
    好处:生成的凭证无法篡改。安全性更高
    缺点:
    1、JWT默认不加密,但可以加密。生成原始令牌后,可以使用改令牌再次对其进行加密。
    2、当JWT未加密方法是,一些私密数据无法通过JWT传输。
    3、JWT不仅可用于认证,还可用于信息交换。善用JWT有助于减少服务器请求数据库的次数。
    4、JWT的最大缺点是服务器不保存会话状态,所以在使用期间不可能取消令牌或更改令牌的权限。也就是说,一旦JWT签发,在有效期内将会一直有效。
    5、JWT本身包含认证信息,因此一旦信息泄露,任何人都可以获得令牌的所有权限。为了减少盗用,JWT的有效期不宜设置太长。对于某些重要操作,用户在使用时应该每次都进行进行身份验证。
    6、为了减少盗用和窃取,JWT不建议使用HTTP协议来传输代码,而是使用加密的HTTPS协议进行传输。

  • author 2.0
    通过请求授权模式进行获取相应的用户信息
    好处:安全可靠,获取的用户数据没有隐私信息
    缺点:编码困难,成本较高

没有100%可靠的算法,暴力破解,穷举
解决方案:

  1. 限制时间内ip登录错误次数
  2. 增加图形验证码,不能过于简单,常用的OCR可以识别验证码

建议:微服务里面,特别是对C端用户的应用,不要做过于复杂的权限校验,特别是影响性能这块

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章