shiro 安全框架

shiro 安全框架

缘由

这周入职了一家新公司,在撸登录认证代码的时候看到了shiro框架,当时对源码一脸懵逼,特意学习了一番,下边是我自己的学习成果及参考前人的总结吐血整理

shiro简介

Apache Shiro 是一个强大且易用的Java安全框架,能够用于身份验证、授权、session管理、加密等功能。

shiro能做什么
  • 验证用户身份
  • 用户访问权限控制 如不同用户对不同url有不同的访问权限
  • 可以响应认证、访问控制
  • 单点登录SSO#### shiro框架

img

Authentication、Authorization、SessionManagement、Crytography 被Shiro框架开发团队称之为应用安全的四大基石。

  • Authentication:认证,用户身份识别,也就是常说的登录

  • Authorization:授权,访问控制,对某个用户授权,判断用户使用权限

  • SessionMangament:特定于用户的会话管理

  • Cryptography:对数据元进行加密

高级概述

在概念层,Shiro架构主要包含三个主要理念:Subject、SecurityManager、Realm。

img

  • **Subject:**当前用户,Subject 可以是一个人,但也可以是第三方服务、守护进程帐户、时钟守护任务或者其它–当前和软件交互的任何事件。
  • **SecurityManager:**管理所有Subject,SecurityManager 是 Shiro 架构的核心,配合内部安全组件共同组成安全伞。
  • **Realms:**用于进行权限信息的验证,我们自己实现。Realm 本质上是一个特定的安全 DAO:它封装与数据源连接的细节,得到Shiro 所需的相关的数据。在配置 Shiro 的时候,你必须指定至少一个Realm 来实现认证(authentication)和/或授权(authorization)。

我们需要实现Realms的Authentication 和 Authorization。其中 Authentication 是用来验证用户身份,Authorization 是授权访问控制,用于对用户进行的操作授权,证明该用户是否允许进行当前操作,如访问某个链接,某个资源文件等。

shiro认证过程

在这里插入图片描述

具体demo:

// 1.构建SecurityManager环境
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
defaultSecurityManager.setRealm(simpleAccountRealm);

// 2.主体提交认证请求
SecurityUtils.setSecurityManager(defaultSecurityManager); // 设置SecurityManager环境
Subject subject = SecurityUtils.getSubject(); // 获取当前主体

UsernamePasswordToken token = new UsernamePasswordToken("wmyskxz", "123456");
subject.login(token); // 登录

这里特别提一点,subject也就是认证的入口,从这个入口点进去,我们就可以知道shiro到底是如何一步一步认证的,我们在写自定义类实现方法是如何运行的
大概流程:

  1. shiro在系统初始化时,一般会在SecurityUtil注入SecurityManager,党委工会的代码是通过xml bean注入的。

  2. 当用户登录时,会从SecurityUtil获取本次登录的主体对象subject

  3. 解析用户登录的用户名及密码,生成token,subject进行登录

    原理流程图如下

    img

    1. 首先调用 Subject.login(token) 进行登录,其会自动委托给 Security Manager,调用之前必须通过 SecurityUtils.setSecurityManager() 设置;
    2. SecurityManager 负责真正的身份验证逻辑;它会委托给 Authenticator 进行身份验证;
    3. Authenticator 才是真正的身份验证者,Shiro API 中核心的身份认证入口点,此处可以自定义插入自己的实现;
    4. Authenticator 可能会委托给相应的 AuthenticationStrategy 进行多 Realm 身份验证,默认 ModularRealmAuthenticator 会调用 AuthenticationStrategy 进行多 Realm 身份验证;
    5. Authenticator 会把相应的 token 传入 Realm,从 Realm 获取身份验证信息,如果没有返回 / 抛出异常表示身份验证失败了。此处可以配置多个 Realm,将按照相应的顺序及策略进行访问。
shiro授权过程

跟认证相似,只不过认证用的是Authenticator,而授权用的是Authorizatior。其他一致。

自定义Realm

从上边的认证及授权流程可以得知,认证和授权都需要借助Realm来实现,Realm也就是我们存储数据的地方,Shiro 框架内部默认提供了两种实现,一种是查询.ini文件的IniRealm,另一种是查询数据库的JdbcRealm。在实际应用中我们会在数据库的基础上进行增强,因此主要记录一下自定义Realm。

public class ShiroDbRealm extends AuthorizingRealm {
    private static Logger log = LogManager.getLogger(ShiroDbRealm.class);

    /**
     * 登录认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
        log.info("Shiro登录认证启动");

        IShiro shiroFactory = ShiroManager.me().getDefaultShiroFactory();
        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;

        User user = shiroFactory.user(token.getUsername());

        if (StrKit.isEmpty(user.getRoleid())) {
            throw new NoRoleException("登录人【" + user.getAccount() + "】没有角色,不能访问系统");
        }

        ShiroUser shiroUser = shiroFactory.shiroUser(user);

        SimpleAuthenticationInfo info = shiroFactory.info(shiroUser, user, getName());

        log.info("Shiro登录认证完毕");
        return info;
    }

    /**
     * 权限认证
     */
    @SuppressWarnings({"rawtypes"})
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        IShiro shiroFactory = ShiroManager.me().getDefaultShiroFactory();
        ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
        Object userId = shiroUser.getId();
        List<Integer> roleList = shiroUser.getRoleList();
        Set<String> urlSet = new HashSet<>();
        Set<String> roleNameSet = new HashSet<>();
        for (Integer roleId : roleList) {
            List<Map> permissions = shiroFactory.findPermissionsByRoleId(userId, roleId);
            if (null != permissions) {
                for (Map map : permissions) {
                    if (!Func.isEmpty(map.get("URL"))) {
                        urlSet.add(Func.toStr(map.get("URL")));
                    }
                }
            }
            String roleName = shiroFactory.findRoleNameByRoleId(roleId);
            roleNameSet.add(roleName);
        }
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermissions(urlSet);
        info.addRoles(roleNameSet);
        return info;
    }

    /**
     * 设置认证加密方式
     */
    @PostConstruct
    public void setCredentialMatcher() {
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName(ShiroKit.hashAlgorithmName);
        credentialsMatcher.setHashIterations(ShiroKit.hashIterations);
        setCredentialsMatcher(credentialsMatcher);
    }

}


看到这里不知道是否有一个疑问:

我们在访问资源的时候shiro是如何进行拦截的。 可以看下边xml里的拦截器配置,shiro是以url为单位进行拦截的,有几个过滤器简称
其中 DefaultWebSecurityManager 的配置可以使用xml的形式配置,也可以使用注解的形式都可以。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值