8.整合shiro

8.1shiroConfig

1. SecurityManager

安全管理器

1.可以说是所有配置的入口,简化配置,方便使用。

2.一个接口就可以实现,验证的操作(登录、退出)、授权(授权访问指定资源、角色)、Session管理。

@Bean
public DefaultWebSecurityManager securityManager() {
   DefaultWebSecurityManager defaultWebSecurityManager;
   (defaultWebSecurityManager = new DefaultWebSecurityManager()).setRealm(this.realm());//将登录用户的认证和权限信息交给securityManager管理
   defaultWebSecurityManager.setSessionManager(this.sessionManager());//将session交给securityManager管理
   defaultWebSecurityManager.setCacheManager( this.redisCacheManager());//将缓存交给securityManager管理
   return defaultWebSecurityManager;
}

2. Realm

主要用作封装认证、授权信息,返回给安全管理器处理

@Bean
public Realm realm() {
   return new UserAuthorizingRealm();
}

3. ShiroFilter

拦截需要安全控制的url,然后进行相应的权限控制。

@Bean

  public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
   ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
   HashMap filters = new HashMap();
   filters.put("rest", new RestShiroFilter());
   shiroFilterFactoryBean.setFilters( filters);
   shiroFilterFactoryBean.setSecurityManager(securityManager);
   LinkedHashMap<String, String> filterChainDefinitionMap;
   (filterChainDefinitionMap = new LinkedHashMap<>()).put("/user", "anon");//可以匿名访问
   filterChainDefinitionMap.put("/captcha", "anon");//可以匿名访问
   filterChainDefinitionMap.put("/captcha/verify", "anon");//可以匿名访问
   filterChainDefinitionMap.put("/user/login", "anon");//可以匿名访问
   filterChainDefinitionMap.put("/user/success", "anon");//可以匿名访问
   filterChainDefinitionMap.put("/swagger-ui.html", "anon");//可以匿名访问
   filterChainDefinitionMap.put("/swagger-resources/**", "anon");//可以匿名访问
   filterChainDefinitionMap.put("/webjars/**", "anon");//可以匿名访问
   filterChainDefinitionMap.put("/druid/**", "anon");//可以匿名访问
   filterChainDefinitionMap.put("/error/**", "anon");//可以匿名访问
   filterChainDefinitionMap.put("/**", "rest");//根据请求的方法
   shiroFilterFactoryBean.setLoginUrl("/error/403"); //没有登录的用户请求到登陆页面的路径
   shiroFilterFactoryBean.setSuccessUrl("/user/success");登录成功的跳转页面
   shiroFilterFactoryBean.setUnauthorizedUrl("/error/403");无权限页面
   shiroFilterFactoryBean.setFilterChainDefinitionMap( filterChainDefinitionMap);
   return shiroFilterFactoryBean;

在ShiroFilterFactoryBean中配置是否认证的规则时,一定要注意使用的容器是否是有序的,shiro根据配置的规则进行拦截认证时,是根据容器中的存储顺序决定的。

项目中使用的是LinkedHashMap。

无权限页面跳转:这个过滤器必须要是AuthorizationFilter过滤器才行,只有perms,roles,ssl,rest,port才是属于AuthorizationFilter,而anon,authcBasic,authc,user是AuthenticationFilter,所以unauthorizedUrl设置后页面不跳转。

 

使用注解注解开发:

//在具体的方法上添加注解
@RequiresRoles(value={“admin”, “user”}, logical= Logical.AND)
@RequiresPermissions(value={“user:select”, “user:all”}, logical= Logical.OR)

若使用注解授权时需注入以下Bean

//自动代理
@Bean
@DependsOn({ "lifecycleBeanPostProcessor" })//指定BeanProcessor 接口
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
   DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
   defaultAAP.setProxyTargetClass(true);
   return defaultAAP;
}
​//通知器用来匹配所有加了认证注解的方法       
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
   AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
   authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
   return authorizationAttributeSourceAdvisor;
}

例如:

4. RedisManager

RedisManager类是由Redis+Jedis+Spring封装而成的,用于操作缓存。

配置关于redis的基本信息

@Bean

    public BaseRedisManager redisManager() {
   if (this.redistype.equals("sentinel")) {
      RedisSentinelManager redisSentinelManager;//redis哨兵管理器监控redis集群
      (redisSentinelManager = new RedisSentinelManager()).setMasterName(this.master);
      redisSentinelManager.setHost(this.nodes);
      redisSentinelManager.setDatabase(this.databaseDefault);
      redisSentinelManager.setPassword(this.password);
      return redisSentinelManager;
   }
   RedisManager redisManager;
   (redisManager = new RedisManager()).setHost(this.host);
   redisManager.setPort(this.port);
   redisManager.setPassword(this.password);
   redisManager.setDatabase(this.databaseDefault);
   return redisManager;
}

5. RedisCacheManager

缓存管理器,RedisCacheManager里实现了shiro中的CacheManager,重写了里面的getCache方法,又实现了Cache方法,重写了里面的get、put、remove等,整合redis的方法,用来实现缓存的持久化。

@Bean

   public RedisCacheManager redisCacheManager() {
   RedisCacheManager redisCacheManager;
   (redisCacheManager = new RedisCacheManager()).setRedisManager( this.redisManager());
   redisCacheManager.setPrincipalIdFieldName("id");//在redis缓存中用于标识用户的字段
   return redisCacheManager;
}

6. SessionManager

SessionManager用于管理Shiro中的Session信息。Session也就是我们通常说的会话,会话是用户在使用应用程序一段时间内携带的数据。传统的会话一般是基于Web容器(如:Tomcat、EJB环境等)。Shiro提供的Session可以在任何环境中使用,不再依赖于其他容器。

SessionManager是shiro提供的完整的会话功能管理器。包括会话的创建、维护、删除、失效、验证等工作。使用redis存储管理session

@Bean

   public SessionManager sessionManager() {
   DefaultWebSessionManager defaultWebSessionManager;
   (defaultWebSessionManager = new DefaultWebSessionManager()).setDeleteInvalidSessions(true);//删除过期的session
   defaultWebSessionManager.setSessionDAO( this.sessionDAO());
   return  defaultWebSessionManager;

7. RedisSessionDAO

RedisSessionDAO的作用是为Session提供CRUD并进行持久化的一个shiro组件

1、AbstractSessionDAO 提供了 SessionDAO 的基础实现,如生成会话ID等。
2、CachingSessionDAO 提供了对开发者透明的会话缓存的功能,需要设置相应的 CacheManager。
3、MemorySessionDAO 直接在内存中进行会话维护
4、EnterpriseCacheSessionDAO 提供了缓存功能的会话维护,默认情况下使用 MapCache 实现,内部使用 ConcurrentHashMap 保存缓存的会话。

5、RedisSessionDao提供了整合redis的会话缓存功能,只需要设置相应的redisManager。

  在doCreate(Session)的时候,会获取一个SessionId,SessoinId是由其属性 sessionIdGenerator 来提供,所以需要配置sessionIdGenerator

@Bean

   public RedisSessionDAO sessionDAO() {
   RedisSessionDAO redisSessionDAO;
   (redisSessionDAO = new RedisSessionDAO()).setRedisManager( this.redisManager());
   redisSessionDAO.setSessionIdGenerator( this.sessionIdGenerator());//设置sessionId
   return redisSessionDAO;
}

JavaUuidSessionIdGenerator

自动生成会话id,生成策略:UUID

@Bean

public JavaUuidSessionIdGenerator sessionIdGenerator() {
   return new JavaUuidSessionIdGenerator();
}

8.2 Realm

自定义Reaml是继承了AuthorizingRealm这个抽象类,它下面是各种操作数据库的实现。

public class UserRealm extends AuthorizingRealm {

@Resource
private UserMapper userMapper;

@Resource
private UserRoleRelationMapper userRoleRelationMapper;

@Resource
private RolePermissionRelationMapper rolePermissionRelationMapper;

@Resource
private RoleMapper roleMapper;

@Resource
private PermissionMapper permissionMapper;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
User user = (User)principalCollection.getPrimaryPrincipal();
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
//查询用户的角色
Set<String> roles = roleMapper.queryAllById(user.getId());
info.setRoles(roles);
//查询用户的权限
Set<String> permissionSet = permissionMapper.queryAllByPermission(user.getId());
info.setStringPermissions(permissionSet);
//返回认证信息
return info;
}
//认证
@SneakyThrows
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//用户名,密码,数据库中获取
UsernamePasswordToken token=(UsernamePasswordToken) authenticationToken;
String username=token.getUsername();
String password=new String(token.getPassword());
if (StringUtils.isEmpty(username) && (StringUtils.isEmpty(password)) ) {
throw new Exception("用户名或密码不能为空");
}
User user = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername, token.getUsername()));
if(ObjectUtils.isEmpty(user)){
throw new Exception("没有该用户");
}
SimpleByteSource simpleByteSource = new SimpleByteSource(user.getSalt());

//SimpleAuthenticationInfo中传入参数:第一个参数可以是当前用户的对象,也可以是用户的姓名,这只是一个身份的表示。(此参数可以通过subject.getPrincipal()方法获取—获取当前记录的用户,从这个用户对象进而再获取一系列的所需要的属性。)第二个参数:传入的是从数据库中获取到的password,然后再与token中的password进行对比,匹配上了就通过,匹配不上就报异常。第三个参数:盐–用于加密密码对比。 若不需要,则可以设置为空 “ ”。第四个参数:当前realm的名字。

//返回认证信息进行密码认证

 return new SimpleAuthenticationInfo(user,user.getPassword(),simpleByteSource,this.getName());
}
}

posted @   我所理解的代码  阅读(251)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示