ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Shiro初级探索

2021-10-04 23:33:33  阅读:131  来源: 互联网

标签:缓存 探索 用户 初级 user new 权限 Shiro


什么是Apache Shiro?

        Apache Shiro 是一个强大而灵活的开源安全框架,可以干净地处理身份验证、授权、企业会话管理和加密。

 shiro可以做的事: 

  • 对用户进行身份验证以验证其身份 
  • 对用户执行访问控制  :     
  1. 确定是否为用户分配了特定的安全角色
  2. 确定是否允许用户做某事
  • 在任何环境中使用会话 API,即使没有 Web 或 EJB 容器
  • 在身份验证、访问控制或会话生命周期期间对事件做出反应。
  • 聚合 1 个或多个用户安全数据的数据源,并将其全部呈现为单个复合用户“视图”。
  • 启用单点登录 (SSO) 功能
  • 无需登录即可为用户关联启用“记住我”服务

Apache Shiro的特性:

Shiro 的目标是 Shiro 开发团队所说的“应用程序安全的四大基石”——身份验证、授权、会话管理和密码学:

  • 身份验证(Authentication):有时也称为“登录”,这是证明用户就是他们所说的身份的行为。

  • 授权(Authorization):访问控制的过程,即确定“谁”可以访问“什么”。

  • 会话管理(Session Management):管理特定于用户的会话,即使是在非 Web 或 EJB 应用程序中。

  • 密码加密(Cryptography):使用密码算法确保数据安全,同时仍然易于使用。

还有一些附加功能:

  • Web支持: Shiro 的 Web 支持 API 有助于轻松保护 Web 应用程序。
  • 缓存(Caching):可确保安全操作保持快速高效。
  • 并发(Concurrency):Apache Shiro 通过其并发特性支持多线程应用程序。
  • 测试(Run As):测试支持可帮助您编写单元和集成测试,并确保您的代码按预期得到保护。
  • 记住我(Remember Me):记住跨会话的用户身份。

Apache Shiro架构:

Shiro 的架构有 3 个主要概念:SubjectSecurityManagerRealms。下图是这些组件如何交互的高级概述,我们将在下面介绍每个概念:

  •  Subject:封装了当前登录用户的信息,并且Subject执行任何操作都必须调用SecurityManager。
  • SecurityManager:是 Shiro 架构的核心,相当于是一个工具箱,调用里面的各种工具(组件),这些组件共同形成一个对象图。
  • Realms:是一个特定的dao,底层访问数据库,并将返回的结果交给SecurityManager,是安全数据与应用程序连接的桥梁。

核心架构图:

 springboot集成了Apache Shiro:

        1.首先添加Shiro Spring web starter依赖:

<dependency>

          <groupId>org.apache.shiro</groupId>

          <artifactId>shiro-spring-boot-web-starter</artifactId>

           <version>1.7.1</version>

</dependency>

        2.启动类或者配置类上添加一个realm对象:

@Bean
public Realm realm() {
  ...
}

         3.设置访问权限拦截器ShiroFilterChainDefinition:

@Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();

        // logged in users with the 'admin' role
        chainDefinition.addPathDefinition("/user/*/*", "anon");//允许匿名访问,并且匿名访问的要放到前面
        chainDefinition.addPathDefinition("/**", "authc");//需要认证方可访问
        // logged in users with the 'document:read' permission

        return chainDefinition;
    }

        4.在Realm中编写认证授权流程:

/**
 * 定义shiro realm对象,基于此对象获取用户认证和授权信息,
 * 假如将来你的项目只做认证,不做授权,则继承继承AuthenticatingRealm对象即可
 */

public class ShiroRealm extends AuthorizingRealm {

    @Autowired
    private SysUserService service;

    @Autowired
    private MenuDao menuDao;

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo
    (PrincipalCollection principalCollection) {

        //获取登录用户
        SysUser user = (SysUser) principalCollection.getPrimaryPrincipal();
        
        //基于登录用户id,查询用户权限
        Set<String> strings = menuDao.selectUserPermissions(user.getId());

        //封装用户权限信息
        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
        info.setStringPermissions(strings);
        return info;
    }


     /**获取并封装认证信息
     * @param authenticationToken 为封装了客户端认证信息的一个令牌对象
     */

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo
    (AuthenticationToken authenticationToken)
            throws AuthenticationException {

        //获取客户端提交的用户名
        String username = ((UsernamePasswordToken) authenticationToken).getUsername();

        //基于用户名查询用户信息并校验
        SysUser user = service.findUserByUsername(username);
        if(user==null)throw new UnknownAccountException();
        if(user.getValid()==0)throw new LockedAccountException();
        
        //封装用户信息
        ByteSource salt = ByteSource.Util.bytes(user.getSalt());
        SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(user,user.getPassword(),salt,getName());
        return info;
    }

    @Override
    public CredentialsMatcher getCredentialsMatcher() {
        //"MD5"为加密的方式
        HashedCredentialsMatcher matcher=new HashedCredentialsMatcher("MD5");
        //"1"代表加密的次数
        matcher.setHashIterations(1);
        return matcher;
    }
}

        5.Controller层通过 SecurityUtils来获取一个Subject对象

 Subject subject = SecurityUtils.getSubject();
 UsernamePasswordToken user=new UsernamePasswordToken(username,password);
 token.setRememberMe(true);//设置记住我
 subject subject.login(user);

通过Subject的login方法提交当前用户信息到ShiroSecrityManger,login方法需要一个token对象,最终是通过Subject对象的login方法将用户的登录信息提交到ShiroSecrityManger中。

        6.授权还需要在Controller层添加@RequiresPermissions("授权标识")

/**

* @RequiresPermissions 描述方法时,此方法为一个授权切入点方法,我们在

* 访问此方法时就需要授权,有权限则可以访问,没有权限则抛出异常。那如何

* 判定用户有没有访问此方法的权限呢?当我们在方法时,shiro框架底层会获取

* 此方法上的 @RequiresPermissions注解,进而取到注解中的权限标识,然后

* 会调用subject对象的checkPermissions(权限标识)方法检测用户是否有权限。

* 这个方法的权限检测调用流程分析?

* subject->SecurityManager-Authorize-->Realm

*/

        如果失效,可能是没有添加:

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setUsePrefix(false);
        return advisorAutoProxyCreator;
    }

这段代码对控制层方法上的注解有效(例如@GetMapping)

        7.缓存的配置:

 /**配置授权缓存管理器,默认应用的缓存是shiro框架内置的缓存对象,
     * 缓存实现就是一个map.*/
    @Bean
    protected CacheManager shiroCacheManager() {
        return new MemoryConstrainedCacheManager();
    }

        这里缓存的是授权标识,标识如果访问的是同一个权限,就不会反复查询数据库权限,提高了程序的效率。

注:如果数据库更改了权限,并且设置了Shiro缓存,呢么就得重启服务或者清除缓存

可能不一定准确,请大神指出不足,谢谢

标签:缓存,探索,用户,初级,user,new,权限,Shiro
来源: https://blog.csdn.net/q2422442709/article/details/120608856

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有