Shiro 自定义验证和授权逻辑

本文详细介绍了Apache Shiro框架在Spring Boot项目中的集成与自定义实现,包括依赖配置、用户验证、权限授权及自定义凭证匹配器的创建,旨在帮助开发者深入理解Shiro的工作原理并掌握其实际应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

依赖

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.5.2</version>
</dependency>

自定义用户验证

  1. 创建MyDBRealm类,继承org.apache.shiro.realm.AuthorizingRealm

  2. 实现doGetAuthenticationInfo()方法,该方法就是验证时获取用户验证信息的核心方法

    下面的方法实现了从数据库获取用户验证信息的逻辑:

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 从token中获取传入的Principal(用户身份信息)
        String userName = (String)authenticationToken.getPrincipal();
        // 根据用户身份信息在数据库中查询用户信息的验证数据(密码)
        Map<String,Object> query = new HashMap<>();
        query.put("user_name",userName);
        List<Employee> emps = employeeMapper.selectByMap(query);
        if (emps == null || emps.size() == 0){
            return null;
        }
        Employee emp = emps.get(0);
        /*
         * 返回一个包含用户信息(可以是用户名或者是一个用户对象,作为Principal)、数据库中的验证数据的SimpleAuthenticationInfo对象
         * 这个对象会在后续的Credentials Matching(证书匹配)过程中将token中的credential和从数据库查到的credential进行对比
         * 匹配则验证成功,不匹配则验证失败
         * */
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(emp,emp.getPassword(),getName());
        return simpleAuthenticationInfo;
    }
    
  3. 配置Shiro

    @Configuration
    public class ShiroConfig {
        @Bean
        public SecurityManager securityManager(){
            DefaultSecurityManager securityManager = new DefaultSecurityManager();
            securityManager.setRealm(myRealm());
            return securityManager;
        }
        @Bean
        public Realm myRealm(){
            MyDBRealm myDBRealm = new MyDBRealm();
            return myDBRealm;
        }
    }
    
  4. 使用

    public void test(){
        SecurityUtils.setSecurityManager(securityManager);
        Subject currentUser = SecurityUtils.getSubject();
        if (!currentUser.isAuthenticated()){
            UsernamePasswordToken token = new UsernamePasswordToken("admin@admin.com","111111");
            try {
                currentUser.login(token);
                log.info("登录成功");
            } catch (UnknownAccountException uae) {
                log.info("There is no user with username of " + token.getPrincipal());
            } catch (IncorrectCredentialsException ice) {
                log.info("Password for account " + token.getPrincipal() + " was incorrect!");
            } catch (LockedAccountException lae) {
                log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                         "Please contact your administrator to unlock it.");
            }
            // ... catch more exceptions here (maybe custom ones specific to your application?
            catch (AuthenticationException ae) {
                //unexpected condition?  error?
            }
            currentUser.logout();
        }
    }
    
  5. 这里的credential比对是默认的简单等值比对,我们可以创建自己的CredentialsMatcher,然后将其配置到Realm

    public class MyCredentialsMatcher implements CredentialsMatcher {
        /**
         * @Description 对md5加密后的Credential进行校验
         * @Param [authenticationToken:登录表单提交的用户验证信息, authenticationInfo:从doGetAuthenticationInfo方法获取大的realm中的用户验证信息]
         * @Return boolean
         * @Author Lrz
         * @date 2020/8/24 15:32
         */
        @Override
        public boolean doCredentialsMatch(AuthenticationToken authenticationToken, AuthenticationInfo authenticationInfo) {
            UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
            String pwd = new String(token.getPassword());
            String md5Pwd = DigestUtils.md5DigestAsHex(pwd.getBytes());
            return authenticationInfo.getCredentials().equals(md5Pwd);
        }
    }
    
    @Bean
    public Realm myRealm(){
        MyDBRealm myDBRealm = new MyDBRealm();
        myDBRealm.setCredentialsMatcher(new MyCredentialsMatcher());
        return myDBRealm;
    }
    

    这样,应用会将提供的Credential进行MD5加密后再与数据库中的数据进行对比。

自定义授权

  1. 在上面创建的MyRealm类中实现doGetAuthorizationInfo方法:

    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        Employee employee = (Employee) principalCollection.getPrimaryPrincipal();
        // 获取用户角色信息
        List<Role> roleList = roleMapper.getRolesByEmpNo(employee.getEmpNo());
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        Set<String> roles = new HashSet<>();
        for (Role role : roleList){
            roles.add(role.getRoleName());
        }
        authorizationInfo.setRoles(roles);
        //获取用户权限信息
        List<String> permissions = permissionMapper.selectByRoles(roleList);
        authorizationInfo.setStringPermissions(new HashSet<String>(permissions));
        return authorizationInfo;
    }
    

    这个方法中,根据当前用户信息获取用户的角色列表和权限列表。

    基于角色的授权

    Subject currentUser = SecurityUtils.getSubject();
    if (currentUser.hasRole("admin")){
        // 验证用户是否是admin
    }
    

    基于权限的授权

    Subject currentUser = SecurityUtils.getSubject();
    if (currentUser.isPermitted("read")){
        // 验证用户是否有read权限
    }
    

与SpringBoot Web的集成

除了上面的定义之外,还需要一个注册一个ShiroFilterChainDefinitionBean

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值