Shiro框架盐值加密配合Springboot进行权限管理

问题描述

使用Shiro框架实现权限管理进行并盐值加密是工作开发最常用的代码,我这里总结成对应的模板,做到即用即拿,CV开发效率变快!


解决方案:

创建springboot项目,创建时选择导入springboot webthmyeleaf(不用不导)

并且导入springshiro的整合包,这里依赖版本要一样,不同版本配置稍微不同

<!--
	Subject用户
	SecurityManager管理所有用户
	Realm连接数据
-->
<!--shiro-spring-->
<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-spring</artifactId>
	<version>1.8.0</version>
</dependency>

数据库模拟,这里用到了权限字段perms,别的具体看自己的业务开发

CREATE TABLE `user`(
	id INT PRIMARY KEY AUTO_INCREMENT,
	username VARCHAR(20),
	pwd VARCHAR(32),
	email VARCHAR(200),
	perms VARCHAR(20)
);

 下面就是基于perms这个权限字段来进行书写

ShiroConfig配置类、UserRealm授权认证类、登录注册类(这个也是重点,如果你用盐值加密注册要盐值加密对应起来,不然检查不了登录不上)

首先ShiroConfig配置类(主要下面的加密配置和引入)

/**
 * @author mrs
 * @create 2022-04-30 17:53
 */
@Configuration
public class ShiroConfig{
    /**
     * MD5或者MD5盐值加密都要注入对应的加密的配置
     * 只要加密都要配!
     * 重点!!
     * @return
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        //setHashAlgorithmName设置使用的加密算法的名称
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
        //设置加密的次数
        hashedCredentialsMatcher.setHashIterations(1024);//这个要与注册那边对应
        return hashedCredentialsMatcher;
    }

    //第一步:创建realm对象,导入对应的加密方式配置
    @Bean
    public UserRealm userRealm(HashedCredentialsMatcher hashedCredentialsMatcher){
        UserRealm userRealm = new UserRealm();
        //替换当前realm对象的credentialsMatcher属性进行密码比对,hashedCredentialsMatcher中对密码加密。
        userRealm.setCredentialsMatcher(hashedCredentialsMatcher);
        return userRealm;
    }
    //第二步:创建安全对象
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联userRealm
        securityManager.setRealm(userRealm);
        return securityManager;
    }
    //第三步:创建过滤工厂ShiroFilerFactoryBeanShiro过滤的一些对象
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);
		/*
			添加内置shiro过滤器
			anon:无需认证就可以访问
			authc:必须认证了才能访问
			user:必须拥有记住我功能才能用
			perms:拥有对某个资源的权限才能访问
			role:拥有某个角色权限才能访问
		*/
        Map<String,String> filterMap = new LinkedHashMap();//这里一定要使用LinkedHashMap!
        //这里一定要放行静态资源!
        //先写小的放行,再写大的放行
        filterMap.put("/static/**","anon");
        filterMap.put("/logout","logout");//设置退出登录请求
        filterMap.put("/bad/vip/**","perms[vip]");//中括号里面就是表示对应权限字段perms的值,进行区分权限!
        filterMap.put("/bad/**","authc");

        bean.setFilterChainDefinitionMap(filterMap);
        bean.setLoginUrl("/index.html");//如果没有登录就调到登陆页面
        bean.setUnauthorizedUrl("/bad/noauth");//权限不够的跳转页面,俗称充钱页面
        return bean;
    }
}

UserRealm授权认证类(设置对应MD5/MD5盐值加密对应的检查机制)

/**
 * @author mrs
 * @create 2022-04-30 17:54
 */
public class UserRealm extends AuthorizingRealm {
    @Autowired
    UserService userService;
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection){
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //拿到当前登录的这个对象
        Subject subject = SecurityUtils.getSubject();
        User currentUser = (User)subject.getPrincipal();
        info.addStringPermission(currentUser.getPerms());
        return info;
    }
    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
            throws AuthenticationException{
        //上面的参数就是authenticationToken就是Controller获取的token
        UsernamePasswordToken userToken = (UsernamePasswordToken)authenticationToken;
        //连接真实的数据库
        User user = userService.queryUserByName(userToken.getUsername());
        if(user==null){//没有这个人
            return null;//抛出异常UnknownAccountException
        }
        /**
         * 密码认证shiro自动配置
         * 密码加密:MD5/MD5盐值加密(建议MD5盐值加密,已经在shiroConfig配置类配置了对应的加密方式)
         * 返回的对象new SimpleAuthenticationInfo(
         *   用户对象,
         *   用户密码(是数据库中查到的注册MD5/MD5盐值加密的加密过的密码),
         *   盐值加密的对象(设置检查对应MD5盐值加密密码的正确性,后面注册是要加密方式一样,不然会验证不了,如果使用MD5加密不写这个参数因为在shiro中已经设置了MD5,这个参数可以省略),
         *   对应的Realm的值(作用不大,一般是对应用户的账号名));
         */
        //创建对应的盐值加密对象,在里面设置对应的盐值,这里加入了对应用户名的大写字符串
        ByteSource bytes = ByteSource.Util.bytes(user.getUsername().toUpperCase());
        return new SimpleAuthenticationInfo(user,user.getPwd(),bytes,user.getUsername());
    }
}

对应写的请求参数的Controller类,其中包括登录、注册、用户权限不够跳转的页面

/**
 * @author mrs
 * @create 2022-04-30 22:07
 */
@Controller
public class IndexController {
    @Autowired
    UserService service;
    @RequestMapping("/tologin")
    public String toLogin(){
        return "index";
    }
    @RequestMapping("/login")
    public String login(String username, String password, Model model, HttpSession session){
        //获取当前用户
        Subject subject = SecurityUtils.getSubject();
        //封装用户的登录数据
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
        try{
            subject.login(token);//执行登录的方法,如果没有异常就说明ok了
            session.setAttribute("loginUser",username);
            return "beddings/dashboard";
        }catch(UnknownAccountException uae){//用户名不对提示
            model.addAttribute("msg","用户名错误");
            return "index";
        }catch(IncorrectCredentialsException ice){//密码不对提示
            model.addAttribute("msg","密码错误");
            return "index";
        }
    }

    /**
     * 俗称,权限不够的请求,跳转充钱页面的请求
     * @return
     */
    @RequestMapping("/bad/noauth")
    public String unauthorized(){
        return "jurisdiction";
    }
    //注册
    @RequestMapping("/regist")
    public String regist(User user,Model model){
        if(service.existsUsername(user.getUsername())){
            /**
             * 这里是注册的重点,在我的shiro检查对应盐值加密的密码时
             * 1、在ShiroConfig类中设置了对应的密码加密设置,参数就是"MD5"和1024
             * 2、在UserRealm类中设置了对应用户名的大写字符串当盐值
             * 所以这四个参数为:MD5、前端接收的密码、用户名的大写字符串(对应的盐值)、1024(对应的加密次数)
             */

            String md5 = new SimpleHash("MD5", user.getPwd(),user.getUsername().toUpperCase(), 1024).toHex();
            user.setPwd(md5);
            service.saveUser(user);
            return "index";
        }else {
           model.addAttribute("msg","用户名重复");
           model.addAttribute("email",user.getEmail());
            return "register";
        }
    }
}

博客中的代码原型是狂神的Shiro框架视频中的结构,这里进行改进加入了一些实际的应用,比如MD5盐值加密等等。如果理解难可以收藏再看B站的狂神Shiro视频,再回来查看会好一点。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值