springboot整合shiro之基本原理[亲测实现]

最近学习了模仿制作天猫商场,做一些必要的笔记,一来是对自己学习的知识的巩固,二来对有同样问题的人有参考作用



一 概述

1 maven配置
 <dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-spring</artifactId>
  <version>1.3.2</version>
 </dependency>
2 核心概念
Subject
代表当前正在执行操作的用户,但Subject代表的可以是人,也可以是任何第三方系统帐号。当然每个subject实例都会被绑定到SercurityManger上。
SecurityManger
SecurityManager是Shiro核心,主要协调Shiro内部的各种安全组件,这个我们不需要太关注,只需要知道可以设置自定的Realm。
Realm
用户数据和Shiro数据交互的桥梁。比如需要用户身份认证、权限认证。都是需要通过Realm来读取数据。
3 主要类

   springboot中集成shiro相对简单,只需要两个类:一个是shiroConfig类,一个是CustonRealm类。

ShiroConfig类
顾名思义就是对shiro的一些配置,相对于之前的xml配置。包括:过滤的文件和权限,密码加密的算法,其用注解等相关功能。
CustomRealm类
自定义的CustomRealm继承AuthorizingRealm,用来实现认证和权限分配,并且重写父类中的doGetAuthorizationInfo(权限相关)、doGetAuthenticationInfo(身份认证)这两个方法。

二 代码实现

1 自定义Realm

   UserService的实现参考我的下一篇文章springboot整合shiro之数据库实现[dbReaml实现]

public class CustomRealm extends AuthorizingRealm {

    @Autowired
    UserService userService;

	/**
	* 进行权限分配
	*/
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        int userId = (Integer) SecurityUtils.getSubject().getPrincipal();
        List<String> roles = userService.getRolesByUser(userId);
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        Set<String> rolesSet = new HashSet<>(roles);
        info.setRoles(rolesSet);
        return info;
    }

    /**
     * 进行身份验证(通俗讲就是登陆验证)
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String userName = (String) authenticationToken.getPrincipal();
        if (StringUtils.isEmpty(userName)){
            throw new AccountException("用户名格式错误");
        }
        User user = userService.get(userName);
        if (user == null){
            throw new AccountException("用户名不存在");
        }
        int userId = user.getId();
        String dbPassword = user.getPassword();
        String salt = user.getSalt();

        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userId, dbPassword, ByteSource.Util.bytes(salt), getName());
        return simpleAuthenticationInfo;
    }

}

特别的:

  • 自定义的Realm类继承AuthorizingRealm类,并且重载doGetAuthorizationInfo和doGetAuthenticationInfo两个方法。
  • doGetAuthorizationInfo: 权限认证,即登录过后,每个身份不一定,对应的所能看的页面也不一样。会在被login()方法自动调用
    doGetAuthenticationInfo:身份认证。即登录通过账号和密码验证登陆人的身份信息。会在权限或角色认证的时候被自动调用
  • SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userId, dbPassword, ByteSource.Util.bytes(salt), getName());中的userId可以随意(因为认证过程只需要密码的匹配,不涉及第一个参数),尽量是你需要的东西,比如大部分人放的是userName用来标识用户,而我放的是userId这样方便在权限分配时候查找数据库。
2 shiroConfig配置
/**
 * @author yangosng
 * @create 2020.04.01
*/

@Configuration
public class ShiroConfig {
    
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //当认证未通过时访问的路径
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/test/login");
        //权限不足时自动跳转的路径
        shiroFilterFactoryBean.setUnauthorizedUrl("/test/notRole");
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
        filterChainDefinitionMap.put("/test/login", "anon");
        filterChainDefinitionMap.put("/", "anon");
        filterChainDefinitionMap.put("/config/addUser", "anon");
        filterChainDefinitionMap.put("/addUser.html", "anon");
        filterChainDefinitionMap.put("/test/notRole", "anon");

        filterChainDefinitionMap.put("/admin/**", "authc,roles[supper]");
        //主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截 剩余的都需要认证
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;

    }

    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
        defaultSecurityManager.setRealm(customRealm());
        return defaultSecurityManager;
    }

    @Bean
    public CustomRealm customRealm() {
        CustomRealm customRealm = new CustomRealm();
        customRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return customRealm;
    }

    /**
     * 配置密码加密
     * md5算法
     * 散列2次
     * @return
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        hashedCredentialsMatcher.setHashIterations(2);
        return hashedCredentialsMatcher;
    }

    /**
     * 开启注解
     */
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * *
     * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
     * 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能
     * * @return
     */
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }

}

特别的:

  • shiroFilter方法
       这个方法看名字就知道了:shiro的过滤器,可以设置登录页面(setLoginUrl)、权限不足跳转页面(setUnauthorizedUrl)、具体某些页面的权限控制或者身份认证。
       注意:这里是需要设置SecurityManager(setSecurityManager)。默认的过滤器还有:anno、authc、authcBasic、logout、noSessionCreation、perms、port、rest、roles、ssl、user过滤器。
       具体的大家可以查看package org.apache.shiro.web.filter.mgt.DefaultFilter。这个类,常用的也就authc、anno。
  • securityManager 方法
       查看源码可以知道 securityManager是一个接口类,我们可以看下它的实现类:
    在这里插入图片描述
       具体怎么实现的,感兴趣的同学可以看下。由于项目是一个web项目,所以我们使用的是DefaultWebSecurityManager ,然后设置自己的Realm。
  • MD5加密
       hashedCredentialsMatcher()是用来配置MD5加密的,千万记住要用customRealm.setCredentialsMatcher(hashedCredentialsMatcher());进行声明,否则验证过正不会被使用,登录验证总是出现用户名密码错误的提示。

三 总结

   shiro最主要的作用就是认证和权限分配。
   如有错误恳请指正,如有侵权请联系我删除
   参考文章: SpringBoot2.0集成Shiro

猜你喜欢

转载自blog.csdn.net/qq_39007083/article/details/105274695