shiro权限验证

上次介绍了shiro的一些理论知识,这次用一些代码来具体实现角色验证与登录验证
首先介绍一下使用的环境:
SpringBoot + Mybatis + Shiro
添加的类

  1. ShiroRealm 继承了AuthorizingRealm类,实现两个方法,分别为登录权限验证,以及角色权限验证的功能。(注释已经很详细了,详细了解请看注释)
import com.aim.chenapp.dao.entity.UserInfoEntity;
import com.aim.chenapp.service.UserInfoService;
import com.fasterxml.jackson.databind.Module;
import org.apache.catalina.Role;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.*;

public class ShiroRealm extends AuthorizingRealm {
    private Logger logger = LoggerFactory.getLogger(ShiroRealm.class);
    @Autowired
    private UserInfoService userInfoService;

    private SimpleAuthenticationInfo info = null;

    /**
     * 1.doGetAuthenticationInfo,获取认证消息,如果数据库中没有数,返回null,如果得到了正确的用户名和密码,
     * 返回指定类型的对象
     *
     * 2.AuthenticationInfo 可以使用SimpleAuthenticationInfo实现类,封装正确的用户名和密码。
     *
     * 3.token参数 就是我们需要认证的token
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    //认证登录
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 1.将token装换成UsernamePasswordToken
        UsernamePasswordToken upToken = (UsernamePasswordToken) authenticationToken;
        logger.info("验证当前Subject时获取到token为:" + upToken.toString());
        // 2.获取用户名即可
        String username = upToken.getUsername();
        // 3.查询数据库,是否查询到用户名和密码的用户
        UserInfoEntity userInfo = userInfoService.selectByPhone(username);

        if(userInfo != null) {
            // 4.如果查询到了,封装查询结果,返回给我们的调用
            Object principal =  userInfo.getPhoneNumber();
            Object credentials = userInfo.getPassword();
            ByteSource salt = ByteSource.Util.bytes(username);
            String realmName = this.getName();
            info = new SimpleAuthenticationInfo(principal, credentials, salt,realmName);
        }else {
            // 5.如果没有查询到,抛出一个异常
            throw new AuthenticationException();
        }
        return info;
    }
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        logger.info("##################执行Shiro权限认证##################");
        String username = (String) principalCollection.getPrimaryPrincipal();
        UserInfoEntity user = userInfoService.selectByPhone(username);
        if (user != null) {
            //权限信息对象info,用来存放查出的用户的所有的角色(role)及权限(permission)
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            //用户的角色集合
            Set<String> list = new HashSet<>();
            list.add(user.getUserType());
            info.addRoles(list);
            //用户的权限集合
            info.addStringPermissions(list);
            return info;
        }
        // 返回null的话,就会导致任何用户访问被拦截的请求时,都会自动跳转到unauthorizedUrl指定的地址
        return null;
    }
}
  1. 定义ShiroConfig类,主要实现定义拦截的接口,不拦截的接口,还有没有权限跳转的接口,以及密码加密的方式等

import com.aim.chenapp.beans.ShiroRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {
    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        System.out.println("ShiroConfiguration.shirFilter()");
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //拦截器.
        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
        // 配置不会被拦截的链接 顺序判断
        //filterChainDefinitionMap.put("user/login", "anon");
//        filterChainDefinitionMap.put("/loginPage.html", "anon");
        //filterChainDefinitionMap.put("/power.html", "anon");
        //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
        filterChainDefinitionMap.put("/user/login", "anon");
        filterChainDefinitionMap.put("/user/unPower", "anon");
        filterChainDefinitionMap.put("/user/doRegister", "anon");
        filterChainDefinitionMap.put("/user/register", "anon");
        filterChainDefinitionMap.put("/csyappService/selectLawyerIndex", "authc,roles[1]");
//        filterChainDefinitionMap.put("/csyappService/selectLawyerIndex", "roles[]");
//        filterChainDefinitionMap.put("/user/doLogout", "logout");
        //<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
        //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
        filterChainDefinitionMap.put("/**", "authc");
        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setLoginUrl("/user/unPower");
        //未授权界面;
//        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    @Bean(name = "myShiroRealm")
    public ShiroRealm myShiroRealm(HashedCredentialsMatcher matcher){
        ShiroRealm myShiroRealm = new ShiroRealm();
//        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher("MD5");
//        matcher.setHashIterations(1024);
        myShiroRealm.setCredentialsMatcher(matcher);
        return myShiroRealm;
    }


    @Bean
    public SecurityManager securityManager(@Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher matcher){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm(matcher));
        return securityManager;
    }

    /**
     * 密码匹配凭证管理器
     *
     * @return
     */
    @Bean(name = "hashedCredentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
          hashedCredentialsMatcher.setHashAlgorithmName("MD5");// 散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(1024);// 散列的次数,比如散列两次,相当于
        return hashedCredentialsMatcher;
    }
}

至此,shiro的配置已经完成,其他的代码都是非常简单的操作,就不一一的写了,相信大家都会。
再次提出一个小小的坑,就是用ajax发送请求,每一次的session都 不同的解决方案,即是:在ajax上添加一个属性

xhrFields: {
            withCredentials: true
            },

这样每次发送的请求session都是一个了,就不会使得验证出现错误。

如有问题,敬请留言。

青春短暂,我_在路上。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
网关整合shiro权限验证是为了增强系统的安全性和权限控制能力。通常情况下,一个系统可能有多个子系统,每个子系统都有自己的权限验证逻辑。如果每个子系统都独立实现权限验证,就会导致代码重复、维护困难以及安全性隐患。因此,将权限验证逻辑集中在网关中进行整合是一个较好的解决方案。 首先,在网关中配置Shiro的拦截器,用于拦截请求并进行权限验证。可以通过配置Shiro的FilterChainDefinitionMap,指定不同的URL需要不同的权限才能访问。这样,当有请求到达网关时,会先经过Shiro拦截器进行权限验证。 其次,网关需要与子系统之间建立安全的通信机制,通常可以采用Token验证机制。当用户登录成功后,网关为其生成一个唯一的Token,并将Token保存在内存或数据库中。当用户访问其他子系统时,将Token作为请求头或请求参数传递给子系统进行验证。子系统收到请求后,可以通过Token获取用户信息,再结合Shiro进行权限验证。 最后,网关还可以实现一些额外的安全功能,例如黑名单/白名单过滤、IP限制、防止重放攻击等。这些功能可以根据具体需求进行定制化开发,并在请求到达网关时进行处理。 通过上述方式,网关可以实现对多个子系统的整合和统一权限验证,减少了代码冗余和维护成本,并提高了系统的整体安全性和可扩展性。同时,通过网关的统一管理,还可以对系统进行监控和日志记录,进一步增强了系统的安全性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值