当前位置: 首页 > news >正文

shiro使用

shiro是apache提供的一种安全框架。他可以将登录,权限这一方面简单化。

使用shiro需要引入

 <dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.9.0</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency>

下图是他所提供的功能。

请添加图片描述

下图是使用层面的三个角色,通过subject也就是用户,将判断交给securityManager,而securityManger会将他交给Realm,也就是判断层。
请添加图片描述
我们可以用shiro为我们提供的realm,也可以重写realm。因为,在实际中,我们的数据都是从数据库中来的,所以我们都是重写realm。

继承AuthorizingRealm,他会让我们重写两个方法,分别是认证,和授权方面的内容。

package com.example.shirodemo;import lombok.val;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.util.ObjectUtils;import java.util.*;public class MyRealm extends AuthorizingRealm {Map<Object, String> userMap = new HashMap<>(16);{userMap.put("cmc", new Md5Hash("123456").toHex());super.setName("myRealm"); // 设置自定义Realm的名称,取什么无所谓..}//    认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {String s = userMap.get(authenticationToken.getPrincipal());UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken;if (!ObjectUtils.isEmpty(s)) {char[] password = usernamePasswordToken.getPassword();Md5Hash md5Hash = new Md5Hash(password);if (s.equals(md5Hash.toHex())){return new SimpleAuthenticationInfo(authenticationToken.getPrincipal(),authenticationToken.getCredentials(),"authentication");}}throw new AuthenticationException("账号或密码错误");}//传进来他的唯一标识,然后根据唯一标识查找他的角色public Set<String> getRolesByUserName(String userName){Set<String> permissions = new HashSet<>();permissions.add("admin");return permissions;}//    认证@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {String userName = (String) principalCollection.getPrimaryPrincipal();// 从数据库获取角色和权限数据Set<String> roles = getRolesByUserName(userName);Set<String> permissions = getPermissionsByUserName(userName);SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();simpleAuthorizationInfo.setStringPermissions(permissions);simpleAuthorizationInfo.setRoles(roles);return simpleAuthorizationInfo;}//根据唯一标识查询他的权限private Set<String> getPermissionsByUserName(String userName) {Set<String> set = new HashSet<>();set.add("*");return set;}
}

我们在实现类中进行判断。

package com.example.shirodemo;import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.codec.Hex;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Test;import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Arrays;public class AuthenticationTest {@Testpublic void testAuthentication() throws UnsupportedEncodingException {// 1.构建SecurityManager环境DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();defaultSecurityManager.setRealm(new MyRealm());// 2.主体提交认证请求SecurityUtils.setSecurityManager(defaultSecurityManager); // 设置SecurityManager环境Subject subject = SecurityUtils.getSubject(); // 获取当前主体String password ="123456";UsernamePasswordToken token = new UsernamePasswordToken("cmc", password);subject.login(token); // 登录// subject.isAuthenticated()方法返回一个boolean值,用于判断用户是否认证成功System.out.println("isAuthenticated:" + subject.isAuthenticated()); // 输出truesubject.checkPermissions("user:add","user:modify");subject.checkRoles("admin");subject.logout(); // 登出Long second = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));//161ea5d3a6218591ba3cc387bf3c8becMd5Hash md5Hash = new Md5Hash(password, String.valueOf(second));System.out.println(md5Hash.toBase64());System.out.println(md5Hash.toHex());System.out.println("isAuthenticated:" + subject.isAuthenticated()); // 输出false}
}

你可以通过使用MD5对密码进行非对称加密。shiro为我们提供了加密对象。

//加密名
//密码
//加入随机数
//加密次数
String encodePassword = new SimpleHash(alogrithmName, password, salt, times).toString();

通过上面的加密方法基本上可以完成非常好的加密了。

如果你想要使用的简单方法的话,使用这个方法即可

String password=new MD5(password,salt).toHex();

shiro的基本使用讲解完了。最重要的还是要和框架融合。
那在spring中应该如何融合呢?

springboot中使用

导包

在你的springboot中加入shiro包。

 <dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.9.0</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope></dependency>

配置

package com.example.shirodemo.config;import com.example.shirodemo.shiro.MyRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.util.ThreadContext;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;@Configuration
public class ShiroConfig {//将自定义的realm丢入ioc中,这里我加入了密码加密//放入securityManager中@Beanpublic DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm realm){DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();//securityManager要完成校验,需要realmsecurityManager.setRealm(realm);ThreadContext.bind(securityManager);//加上这句代码手动绑定return securityManager;}@Beanpublic ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){ShiroFilterFactoryBean filter=new ShiroFilterFactoryBean();filter.setSecurityManager(defaultWebSecurityManager);//设置shiro的拦截规则//anon 匿名用户可访问   authc  认证用户可访问//user 使用RemeberMe的用户可访问  perms  对应权限可访问//role  对应的角色可访问Map<String,String> filterMap=new HashMap<>();filterMap.put("/login","anon");filterMap.put("/register","anon");filterMap.put("static/**","anon");filterMap.put("/**","authc");filter.setFilterChainDefinitionMap(filterMap);//设置未授权页面跳转到登录页面filter.setUnauthorizedUrl("/unauthorized");return filter;}//使Shiro的注解可以加载执行@Beanpublic DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){DefaultAdvisorAutoProxyCreator autoProxyCreator=new DefaultAdvisorAutoProxyCreator();autoProxyCreator.setProxyTargetClass(true);return autoProxyCreator;}//权限注解加载@Beanpublic AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager defaultWebSecurityManager){AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor();advisor.setSecurityManager(defaultWebSecurityManager);return advisor;}//加入密码的暗文判断@Beanpublic HashedCredentialsMatcher getHashedCredentialsMatcher(){HashedCredentialsMatcher matcher=new HashedCredentialsMatcher();//matcher就是用来指定加密规则//加密方式matcher.setHashAlgorithmName("md5");//hash次数,这里的hash次数要与存储时加密的hash次数保持一致matcher.setHashIterations(1);return matcher;}@Beanpublic MyRealm getMyRealm(HashedCredentialsMatcher matcher){MyRealm myRealm = new MyRealm();myRealm.setCredentialsMatcher(matcher);return myRealm;}
}

里面加入了生效注解,我们可以直接使用注解了。

声明一个处理全局异常的类,用来接受无权限的报错

package com.example.shirodemo.shiro;import com.example.shirodemo.entity.sys.User;
import com.example.shirodemo.service.UserService;
import jakarta.annotation.Resource;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;public class MyRealm extends AuthorizingRealm {@ResourceUserService userService;//    认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {System.out.println(authenticationToken.getPrincipal());User user = userService.lambdaQuery().eq(User::getUsername, authenticationToken.getPrincipal()).one();if (ObjectUtils.isEmpty(user)){return null;}//e10adc3949ba59abbe56e057f20f883ereturn new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),"");}//传进来他的唯一标识,然后根据唯一标识查找他的角色public Set<String> getRolesByUserName(String userName){Set<String> permissions = new HashSet<>();permissions.add("admin");return permissions;}//    认证@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {String userName = (String) principalCollection.getPrimaryPrincipal();// 从数据库获取角色和权限数据Set<String> roles = getRolesByUserName(userName);Set<String> permissions = getPermissionsByUserName(userName);SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();simpleAuthorizationInfo.setStringPermissions(permissions);simpleAuthorizationInfo.setRoles(roles);return simpleAuthorizationInfo;}//根据唯一标识查询他的权限private Set<String> getPermissionsByUserName(String userName) {Set<String> set = new HashSet<>();return set;}
}

realm你可以自己进行更改。你还可以加入加密规则。

@Beanpublic HashedCredentialsMatcher getHashedCredentialsMatcher(){HashedCredentialsMatcher matcher=new HashedCredentialsMatcher();//matcher就是用来指定加密规则//加密方式matcher.setHashAlgorithmName("md5");//hash次数,这里的hash次数要与存储时加密的hash次数保持一致matcher.setHashIterations(1);return matcher;}//自定义Realm@Beanpublic MyRealm getMyRealm(HashedCredentialsMatcher matcher){MyRealm myRealm=new MyRealm();//设置加密规则myRealm.setCredentialsMatcher(matcher);return myRealm;}

相关文章:

  • 汽车行驶工况特征参数:从“速度曲线”到“驾驶DNA”的硬核解码
  • 原型模式详解及c++代码实现(以自动驾驶感知场景为例)
  • 如何使用Python进行自动化的系统管理?
  • 布隆过滤器如何删除数据
  • 【认知觉醒】是什么? 如何做到 ? ( 持续更新ing )
  • FPGA(现场可编程门阵列)笔记
  • DDS Discovery数据
  • STL简介 + string【上】
  • Python环境中在线训练机器学习模型所遇到的问题及解决方案
  • 不确定与非单调推理的概率方法
  • 2025年大一训练-DP1
  • WebSocket:实现实时双向通信的技术
  • 网络安全-Burp Suite基础篇
  • 手持式三维扫描设备赋能智能汽车制造
  • 第五章 SQLite数据库:5、SQLite 进阶用法:JOIN、UNION、TRIGGER、INDEX、ALIAS、INDEXED BY 等模块
  • 大屏设计与汇报:政务服务可视化实践
  • RUI桌面TV版最新版免费下载-安卓电视版使用教程
  • 2025年03月中国电子学会青少年软件编程(Python)等级考试试卷(二级)真题
  • LIB-ZC, 一个跨平台(Linux)平台通用C/C++扩展库, stream 流操作
  • Windows 11设置开机自动运行 .jar 文件
  • 上海明天有雷雨、大风,下周气温在春日舒适区间
  • 美军一天内对也门发动50余次袭击,胡塞武装称再次击落美军无人机
  • 女子伸腿阻止高铁关门被拘,央媒:严格依规公开处理以儆效尤
  • 北理工再通报:开除宫某党籍,免去行政职务,解除聘用关系
  • 两名中国公民在墨尔本被海浪卷走,我领馆发文提醒
  • 福特预期6月美国市场涨价,机构称加税让每辆汽车成本至少增加数千美元