本笔记基于B站UP主不良人编程

目录

1.权限的管理

1.1什么是权限管理

1.2什么是身份认证

1.3什么是授权

2.什么是Shiro

3.Shiro的核心架构

3.1 S核心内容

4.shiro中的认证4.1认证

4.2shiro中认证的关键对象

4.3认证流程

4.4认证程序开发流程

4.4认证程序源码

4.5自定义Realm

4.6使用DM5和Salt

5.shiro中的授权

5.1授权

5.2关键对象

5.3授权流程

5.4授权方式

5.5权限字符串

5.6 shiro中授权编程实现方式

5.7开发授权

6基于SpringBoot整合

6.1引入shiro依赖

6.2配置shiro环境

6.3MD5、Salt的认证实现

6.4shiro中授权编程实现方式-代码实现

6.5.shiro整合springboot之授权数据的数据库获取

6.8使用CacheManager1.Cache作用

2.使用shiro中默认EhCache实现缓存

6.9Shiro整合springboot缓存之Redis


1.权限的管理

1.1什么是权限管理

基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略 控制用户可以访问而且只能访问自己被授权的资源。
  权限管理包括用户身份认证授权两部分,简称认证授权。对于需要访问控制的资源用户首先经过身份认证,认证通过后用户具有该资源的访问权限方可访问。

1.2什么是身份认证

身份认证,就是判断一个用户是否为合法用户的处理过程。最常用的简单身份认证方式是系统通过核对用户输入的用户名和口令,看其是否与系统中存储的该用户的用户名和口令一致,来判断用户身份是否正确。对于采用指纹等系统,则出示
指纹;对于硬件Ky等刷卡系统,则需要刷卡。

1.3什么是授权

授权,即访问控制,控制谁能访问哪些资源。主体进行身份认证后需要分配权限方可访问系统的资源,对于某些资源没权限是无法访问的

2.什么是Shiro

Apache Shiro是一个功能强大且易于使用的 Java 安全框架,它执行身份验证、授权、加密和会话管理。使用 Shiro 易于理解的 APl,您可以快速而轻松地保护任何应用程序——从最小的移动应用程序到最大的 Web 和企业应用程序

3.Shiro的核心架构

3.1 S核心内容

Subject(用户):当前的操作用户 获取当前用户Subject currentUser = SecurityUtils.getSubject()
SecurityManager(安全管理器):Shiro的核心,负责与其他组件进行交互,实现 subject 委托的各种功能
Realms(数据源) :Realm会查找相关数据源,充当与安全管理间的桥梁,经过Realm找到数据源进行认证,授权等操作
Authenticator(认证器): 用于认证,从 Realm 数据源取得数据之后进行执行认证流程处理。
Authorizer(授权器):用户访问控制授权,决定用户是否拥有执行指定操作的权限。
SessionManager (会话管理器):支持会话管理
CacheManager (缓存管理器):用于缓存认证授权信息
Cryptography(加密组件):提供了加密解密的工具包

4.shiro中的认证
4.1认证

身份认证,就是判断一个用户是否为合法用户的处理过程。最常用的简单身份认证方式是系统通过核对用户输入的用户名和口令,看其是否与系统中存储的该用户的用户名和口令一致,来判断用户身份是否正确。

4.2shiro中认证的关键对象

Subject:主体
访问系统的用户,主体可以是用户、程序等,进行认证的都称为主体;
Principal:身份信息
是主体(subject)进行身份认证的标识,标识必须具有唯一性,如用户名、手机号、邮箱地址等,一个主体可以有多个身份,但是必须有一个主身份(PrimaryPrincipal)
“credential:凭证信息!
是只有主体自己知道的安全信息,如密码、证书等。

4.3认证流程

4.4认证程序开发流程

注意点:shiro配置文件
.ini结尾文件   .txt   .ini复杂数据格式

shiro配置文件

[users]
hzw=123
zhangsan=123456
ryw=1233

shiro所需依赖

    <dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.3.2</version></dependency>
package com.hzw.shiro;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;public class Authenticator {public static void main(String[] args) {//1.创建安全管理器对象 ctrl +h 看结构图DefaultSecurityManager securityManager=new  DefaultSecurityManager();//2.安全管理系设置 RealmsecurityManager.setRealm(new IniRealm("classpath:shiro.ini"));//3.SecurityUtils 全局安全工具类设置安全管理器SecurityUtils.setSecurityManager(securityManager);//4.Subject:主体Subject subject = SecurityUtils.getSubject();//5.创建令牌UsernamePasswordToken token = new UsernamePasswordToken("hzw", "123");try {System.out.println("认证状态"+subject.isAuthenticated());//登录subject.login(token);System.out.println("认证状态"+subject.isAuthenticated());//退出登录subject.logout();System.out.println("认证状态"+subject.isAuthenticated());} catch ( UnknownAccountException e) {e.printStackTrace();System.out.println("用户名不存在");}catch (IncorrectCredentialsException e){e.printStackTrace();System.out.println("密码错误");}}
}

测试结果

4.4认证程序源码

认证:
1.最终执行用户名比较SimpleAccountRealm
doGetAuthenticationInfo在这个方法中完成用户名校验
2.最终密码校验是在AuthenticatingRealm中
assertCredentialsMatch

总结

AuthenticatingRealm   认证realm   doGetAuthenticationInfo
AuthorizingRealm   授权realm   doGetAuthorizationInfo

4.5自定义Realm

实现代码

自定义Realm

package com.hzw.shiro.realm;import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;//自定义realm实现将认证/授权数据的来源转为数据库的实现
public class CustomerRealm extends AuthorizingRealm {@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {return null;}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {//token获取用户名String principal = (String) token.getPrincipal();System.out.println(principal);//判断if ("hzw".equals(principal)){//SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal, "123", this.getName());return simpleAuthenticationInfo;}return null;}
}

测试代码

package com.hzw.shiro.realm;import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;public class RealmTest {public static void main(String[] args) {//1.创建安全管理器对象 ctrl +h 看结构图DefaultSecurityManager securityManager=new  DefaultSecurityManager();//2.安全管理系设置 Realm// securityManager.setRealm(new IniRealm("classpath:shiro.ini"));//2.自定义RealmsecurityManager.setRealm(new CustomerRealm());//3.SecurityUtils 全局安全工具类设置安全管理器SecurityUtils.setSecurityManager(securityManager);//4.Subject:主体Subject subject = SecurityUtils.getSubject();//5创建令牌UsernamePasswordToken token = new UsernamePasswordToken("hzw", "123");try {//登录subject.login(token);System.out.println("认证状态"+subject.isAuthenticated());} catch ( UnknownAccountException e) {e.printStackTrace();System.out.println("用户名不存在");}catch (IncorrectCredentialsException e){e.printStackTrace();System.out.println("密码错误");}}
}

4.6使用DM5和Salt

实际应用是将盐和散列后的值存在数据库中,自动realm从数据库取出盐和加密后的值由shr©完成密码校验。

依赖

  <dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.3.2</version></dependency>

MD5、salt、hash密文

package com.hzw.shiro;import org.apache.shiro.crypto.hash.Md5Hash;public class Md5Test {public static void main(String[] args) {//使用md5Md5Hash md5Hash  =new Md5Hash("123");System.out.println(md5Hash.toHex());
//使用MD5+sa1t处理Md5Hash md5Hash1 = new Md5Hash("123","XO*7ps");System.out.println(md5Hash1.toHex());
//使用md5+sa1t+hash散列Md5Hash md5Hash2 =new Md5Hash("123","XO*7ps",1024);System.out.println(md5Hash2.toHex());}
}

获取加密后的密码,接下来测试md5、md5+salt、md5+salt+hash

package com.hzw.shiro.realm;import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;import javax.annotation.Resource;public class CustomerMd5Realm extends AuthorizingRealm {@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {return null;}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {//获取身份信息String principal = (String) token.getPrincipal();//根据用户名if ("hzw".equals(principal)) {//return new SimpleAuthenticationInfo(principal,"202cb962ac59075b964b07152d234b70",// ByteSource.Util.bytes("XO*7ps"),  //+salt 密文this.getName());}return null;}
}

自定义Realm

package com.hzw.shiro;import com.hzw.shiro.realm.CustomerMd5Realm;
import com.hzw.shiro.realm.CustomerRealm;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;public class MD5Authenit {public static void main(String[] args) {//1.创建安全管理器对象 ctrl +h 看结构图DefaultSecurityManager securityManager=new  DefaultSecurityManager();//2.自定义RealmCustomerMd5Realm md5Realm = new CustomerMd5Realm();//设置realm 使用hash凭借匹配器HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();//使用算法credentialsMatcher.setHashAlgorithmName("md5");//hash列//  credentialsMatcher.setHashIterations(1024);//set进去md5Realm.setCredentialsMatcher(credentialsMatcher);securityManager.setRealm(md5Realm);//3.SecurityUtils 全局安全工具类设置安全管理器SecurityUtils.setSecurityManager(securityManager);//4.Subject:主体Subject subject = SecurityUtils.getSubject();//5创建令牌UsernamePasswordToken token = new UsernamePasswordToken("hzw", "123");try {//登录subject.login(token);System.out.println("登录成功");} catch ( UnknownAccountException e) {e.printStackTrace();System.out.println("用户名不存在");}catch (IncorrectCredentialsException e){e.printStackTrace();System.out.println("密码错误");}}
}

测试md5

5.shiro中的授权

5.1授权

授权,即访问控制,控制谁能访问哪些资源。主体进行身份认证后需要分配权限方可访问系统的资源,对于某些资源没
有权限是无法访问的。

5.2关键对象

授权可简单理解为who对what(which)进行How操作
Who,即主体(Subject),主体需要访问系统中的资源。
What,即资源(Resource),如系统菜单、页面、按钮、类方法、系统商品信息等。资源包括资源类型资源实例,比如商品信息为资源类型,类型为t01的商品为资源实例,编号为001的商品信息也属于资源实例。
HoW,权限/许可(Permission),规定了主体对资源的操作许可,权限离开资源没有意义,如用户查询权限、用户添加权限、某个类方法的调用权限、编号为001用户的修改权限等,通过权限可知主体对哪些资源都有哪些操作许可。

5.3授权流程

5.4授权方式

5.5权限字符串

权限字符串的规则是:资源标识符:操作:资源实例标识符,意思是对哪个资源的哪个实例具有什么操作,“:”是资源/操作/实例的分割符,权限字符串也可以使用通配符。
例子:
·用户创建权限:user:create,或user:create:*
·用户修改实例001的权限:user:update:001
·用户实例001的所有权限:user:*:001

5.6 shiro中授权编程实现方式

5.7开发授权

//shiro所需依赖

    <dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.3.2</version></dependency>

//自定义realm

package com.hzw.shiro.realm;import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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 javax.annotation.Resource;public class CustomerMd5Realm extends AuthorizingRealm {//授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {String principal = (String) principals.getPrimaryPrincipal();System.out.println("身份信息"+principal);//根据身份信息 用户名 获取当前用户的角色信息, 以及权限信息 xiaoehen admin userSimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();//将数据库查询角色信息赋值给权限对象simpleAuthorizationInfo.addRole("admin");simpleAuthorizationInfo.addRole("user");//将数据库中查询权限信息赋值给权限对象simpleAuthorizationInfo.addStringPermission("user:*:01");simpleAuthorizationInfo.addStringPermission("produce:create");return simpleAuthorizationInfo;}
//认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {//获取身份信息String principal = (String) token.getPrincipal();//根据用户名if ("hzw".equals(principal)) {//参数1:数据库用户名参数2:数据库md5+salt之后的密码参数3:注册时的随机盐参数4:realm的名字return new SimpleAuthenticationInfo(principal,"908da6d8e6057542323d9f58de42f9ab",ByteSource.Util.bytes("XO*7ps"),  //+salt 密文this.getName());}return null;}
}

//

package com.hzw.shiro;import com.hzw.shiro.realm.CustomerMd5Realm;
import com.hzw.shiro.realm.CustomerRealm;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;import java.util.Arrays;public class MD5Authenit {public static void main(String[] args) {//1.创建安全管理器对象 ctrl +h 看结构图DefaultSecurityManager securityManager=new  DefaultSecurityManager();//2.自定义RealmCustomerMd5Realm md5Realm = new CustomerMd5Realm();//设置realm 使用hash凭借匹配器HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();//使用算法credentialsMatcher.setHashAlgorithmName("md5");//hash列credentialsMatcher.setHashIterations(1024);//set进去md5Realm.setCredentialsMatcher(credentialsMatcher);securityManager.setRealm(md5Realm);//3.SecurityUtils 全局安全工具类设置安全管理器SecurityUtils.setSecurityManager(securityManager);//4.Subject:主体Subject subject = SecurityUtils.getSubject();//5创建令牌UsernamePasswordToken token = new UsernamePasswordToken("hzw", "123");try {//登录subject.login(token);System.out.println("登录成功");} catch ( UnknownAccountException e) {e.printStackTrace();System.out.println("用户名不存在");}catch (IncorrectCredentialsException e){e.printStackTrace();System.out.println("密码错误");}if (subject.isAuthenticated()){//基于角色权限控制System.out.println("====单角色====");System.out.println(subject.hasRole("admin"));System.out.println("====多角色====");//基于多角色权限控制System.out.println(subject.hasAllRoles(Arrays.asList("admin", "user")));System.out.println("====是否具有其中一个角色====");//是否具有其中一个角色boolean[] booleans= subject.hasRoles(Arrays.asList("admin","super","user"));for (boolean aBoolean : booleans) {System.out.println(aBoolean);}}System.out.println("======权限信息");//基于权限字符串的访问控制,资源标识符:操作:资源类型System.out.println("权限:"+subject.isPermitted("user:*:01"));System.out.println("权限:"+subject.isPermitted("produce:create:01"));//分别具有哪些权限boolean[] permitted = subject.isPermitted("user:*:01", "user:*:04");for (boolean b : permitted) {System.out.println(b);}//同时具有哪些权限System.out.println("===同时具有哪些权限===");boolean permittedAll = subject.isPermittedAll("user:*:01", "produce:create:01");System.out.println(permittedAll);}
}

6基于SpringBoot整合

整合思路

创建springboot项目

6.1引入shiro依赖

<!--引入jsp解析--><dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId></dependency><!--引入shiro整合springboot依赖--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring-boot-web-starter</artifactId><version>1.5.3</version></dependency>

6.2配置shiro环境

1.创建shiro配置类

1.1配置ShiroFilterFactoryBean

1.2配置DefaultWebSecurityManager

1.4自定义Realm

package com.hzw.config;import com.hzw.shiro.CustomerRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.HashMap;@Configuration
public class ShiroConfig  {//1.创建shiroFilter所有拦截请求@Bean(name = "shiroFilterFactoryBean")public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();//给filter设置安全管理器shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);//配置系统受限资源//配置系统公共资源HashMap<String, String> map = new HashMap<>();map.put("/index.jsp","authc");  //authc 请求这个资源要认证和授权//默认认证界面路径shiroFilterFactoryBean.setLoginUrl("/login.jsp");shiroFilterFactoryBean.setFilterChainDefinitionMap(map);return shiroFilterFactoryBean;}//2.创建安全管理器@Beanpublic DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm){DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();//给安全管理器设置defaultWebSecurityManager.setRealm(realm);return defaultWebSecurityManager;}//3.创建自定义realm@Beanpublic Realm realm(){CustomerRealm customerRealm = new CustomerRealm();return customerRealm;}}

1.3创建自定义shiro

package com.hzw.shiro;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
public class CustomerRealm extends AuthorizingRealm {@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {return null;}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {System.out.println("================");String principal = (String)token.getPrincipal();if ("hzw".equals(principal)){return new SimpleAuthenticationInfo(principal,"123",this.getName());}return null;}
}

1.5编写控制器跳转至index.html

package com.hzw.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
public class UserController {@RequestMapping("/logout")public String logout(){Subject subject = SecurityUtils.getSubject();subject.logout();return "redirect:/login.jsp";}/*** 处理身份认证* @param username* @param password* @return*/@RequestMapping("/login")public String login(String username,String password){//获取主题对象Subject subject = SecurityUtils.getSubject();try {subject.login(new UsernamePasswordToken(username,password));return "redirect:/index.jsp";}catch (UnknownAccountException e){e.getStackTrace();System.out.println("用户名错误");}catch (IncorrectCredentialsException e){e.getStackTrace();System.out.println("密码错误");}return "redirect:/login.jsp";}
}

index.jsp

<%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
<!doctype html>
<head><meta charset="UTF-8"><meta name="viewport"content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>首页</title>
</head>
<body>
<h1>系统主页</h1>
<a href="${pageContext.request.contextPath}/user/login">退出登录</a>
<ul style="list-style: none"><li><a href="">用户管理</a></li><li><a href="">商品管理</a></li><li><a href="">订单管理</a></li><li><a href="">物流管理</a></li>
</ul>
</body>
</html>

login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>登录</title>
</head>
<body>
<h2>VIP用户登录</h2>
<form action="${pageContext.request.contextPath}/user/logout" method="post">用户名:<input type="text" name="username"><br/>密码:<input type="text" name="password"><br/><input type="submit" value="登录">
</form>
</body>
</html>

1.6启动测试

登录 输入正确密码 跳转到index.jsp

1.7加入权限控制

package com.hzw.config;import com.hzw.shiro.CustomerRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.HashMap;@Configuration
public class ShiroConfig  {//1.创建shiroFilter所有拦截请求@Bean(name = "shiroFilterFactoryBean")public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();//给filter设置安全管理器shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);HashMap<String, String> map = new HashMap<>();//配置系统公共资源map.put("/user/login","anon");//配置系统受限资源map.put("/**","authc");   //authc 请求这个资源要认证和授权//默认认证界面路径shiroFilterFactoryBean.setLoginUrl("/login.jsp");shiroFilterFactoryBean.setFilterChainDefinitionMap(map);return shiroFilterFactoryBean;}//2.创建安全管理器@Beanpublic DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm){DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();//给安全管理器设置defaultWebSecurityManager.setRealm(realm);return defaultWebSecurityManager;}//3.创建自定义realm@Beanpublic Realm realm(){CustomerRealm customerRealm = new CustomerRealm();return customerRealm;}}

6.4常见过滤器

6.3MD5、Salt的认证实现

1.开发数据库注册

0  开发注册界面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body>
<h1>用户注册</h1>
<form action="${pageContext.request.contextPath}/user/register" method="post">用户名:<input type="text" name="username"><br/>密码:  <input type="text" name="password" ><br/><input type="submit" value="用户注册"></form>
</body>
</html>

1.创建数据库表结构

2.引入依赖

<!--引入jsp解析--><dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId></dependency><!--引入shiro整合springboot依赖--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring-boot-web-starter</artifactId><version>1.5.3</version></dependency><!--mybatis--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.1</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.17</version></dependency><!--druid--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.16</version></dependency>

3.配置application.properties配置文件

server.port=8888
server.servlet.context-path=/shiro
spring.application.name=shiro
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/shiro?useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root
mybatis.type-aliases-package=com.hzw.entry
mybatis.mapper-locations=classpath:com/hzw/mapper/*.xml
logging.level.com.hzw.dao=debug

4.创建entry

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class User {private int id;private String username;private String password;private String salt;
}

5.创建dao接口


import com.hzw.entry.User;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface UserDao {//保存void save(User user);//根据用户名查询业务的方法User findByUserName(String username);
}

6.开发mappper配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hzw.dao.UserDao"><insert id="save" parameterType="com.hzw.entry.User" useGeneratedKeys="true" keyProperty="id">insert into user(username,password,salt) values (#{username},#{password},#{salt})</insert><select id="findByUserName" resultType="com.hzw.entry.User" parameterType="String">select id,username,password,salt from userwhere username=#{username}</select></mapper>

7.开发service接口和实现类

import com.hzw.entry.User;public interface UserService {//注册用户方法void register(User user);//根据用户名查询业务的方法User findByUserName(String username);
}
package com.hzw.service.impl;import com.hzw.dao.UserDao;
import com.hzw.entry.User;
import com.hzw.service.UserService;
import com.hzw.utils.SaltUtils;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service("userService")
@Transactional
public class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao;@Overridepublic void register(User user) {//1.生成saltString salt = SaltUtils.getSalt(8);System.out.println(salt);//2.保存user.setSalt(salt);//3.明文密码:md5+salt+hashMd5Hash md5Hash = new Md5Hash(user.getPassword(),salt,1024);user.setPassword(md5Hash.toHex());System.out.println(md5Hash);userDao.save(user);}@Overridepublic User findByUserName(String username) {return userDao.findByUserName(username);}}

8.创建utils工具类

//获取salt随机盐

import java.util.Random;public class SaltUtils {public static String getSalt(int n){char[] chars="ABCDEFGHIJKLMNOPORSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890!@#&*()".toCharArray();StringBuilder stringBuilder = new StringBuilder();for (int i = 0; i <n ; i++) {char aChar=chars[new Random().nextInt(chars.length)];stringBuilder.append(aChar);}return stringBuilder.toString();}public static void main(String[] args) {String salt = getSalt(8);System.out.println(salt);}}

//根据bean名字获取bean对象

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class AppliactionContextUtils implements ApplicationContextAware {private static ApplicationContext context;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.context=applicationContext;}//根据bean名字获取工厂指定bean对象public  static Object getBean(String beanName){Object bean = context.getBean(beanName);return bean;}
}

9.解密 密文 避免登录失败 因为密码与数据库密码不一致

import com.hzw.shiro.CustomerRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.HashMap;@Configuration
public class ShiroConfig  {//1.创建shiroFilter所有拦截请求@Bean(name = "shiroFilterFactoryBean")public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();//给filter设置安全管理器shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);HashMap<String, String> map = new HashMap<>();map.put("/user/login","anon");         //配置系统公共资源map.put("/user/register","anon");         //配置系统公共资源map.put("/register.jsp","anon");         //配置系统公共资源//配置系统受限资源map.put("/**","authc");   //authc 请求这个资源要认证和授权//默认认证界面路径shiroFilterFactoryBean.setLoginUrl("/login.jsp");shiroFilterFactoryBean.setFilterChainDefinitionMap(map);return shiroFilterFactoryBean;}//2.创建安全管理器@Beanpublic DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm){DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();//给安全管理器设置defaultWebSecurityManager.setRealm(realm);return defaultWebSecurityManager;}//3.创建自定义realm@Beanpublic Realm realm(){CustomerRealm customerRealm = new CustomerRealm();//hash凭证校验匹配器HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();//设置加密算法为MD5credentialsMatcher.setHashAlgorithmName("MD5");//设置散列次数credentialsMatcher.setHashIterations(1024);customerRealm.setCredentialsMatcher(credentialsMatcher);return customerRealm;}}

9自定义realm

package com.hzw.shiro;
import com.hzw.entry.User;
import com.hzw.service.UserService;
import com.hzw.utils.AppliactionContextUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.util.ObjectUtils;
public class CustomerRealm extends AuthorizingRealm {@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {return null;}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {System.out.println("================");//根据String principal = (String)token.getPrincipal();UserService userService =(UserService)AppliactionContextUtils.getBean("userService");User user = userService.findByUserName(principal);System.out.println(principal);if (!ObjectUtils.isEmpty(user)){return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),ByteSource.Util.bytes(user.getSalt()),this.getName());}return null;}
}

10.开发controller

package com.hzw.controller;
import com.hzw.entry.User;
import com.hzw.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("user")
public class UserController {@Autowiredprivate UserService userService;@RequestMapping("register")public String register(User user){try {userService.register(user);return "redirect:/login.jsp";}catch (Exception e){e.printStackTrace();return "redirect:/register.jsp";}}/*** 退出登录* @return*/@RequestMapping("logout")public String logout(){Subject subject = SecurityUtils.getSubject();subject.logout();return "redirect:/login.jsp";}/*** 处理身份认证* @param username* @param password* @return*/@RequestMapping("/login")public String login(String username,String password){//获取主题对象Subject subject = SecurityUtils.getSubject();try {subject.login(new UsernamePasswordToken(username,password));return "redirect:/index.jsp";}catch (UnknownAccountException e){e.getStackTrace();System.out.println("用户名错误");}catch (IncorrectCredentialsException e){e.getStackTrace();System.out.println("密码错误");}return "redirect:/login.jsp";}
}

11.密文加密 运行成功

6.4shiro中授权编程实现方式-代码实现

编程和注解方式

package com.hzw.controller;import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
@RequestMapping("order")
public class ShiroController {//使用注解来判断是否具有权限@RequestMapping("save")//@RequiresRoles("user")   //用来判断角色 具有user@RequiresRoles({"user,admin"})  //用来判断角色 同时具有多个角色@RequiresPermissions("user:update:01")  //用来判断权限字符串public String save(){Subject subject = SecurityUtils.getSubject();//编程if (subject.hasRole("user")){System.out.println("保存成功");}else {System.out.println("无权访问");}return "redirect:/index.jsp";}}

3.标签

加上shiro标签头

<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<!doctype html>
<head><meta charset="UTF-8"><meta name="viewport"content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>首页</title>
</head>
<body>
<h1>系统主页</h1>
<a href="${pageContext.request.contextPath}/user/logout">退出登录</a>
<ul style="list-style: none"><%--角色授权--%><shiro:hasRole name="user"><li><a href="">用户管理</a></li><ul><%--资源授权--%><shiro:hasPermission name="user:add:*"><li><a href="">添加</a></li></shiro:hasPermission><shiro:hasPermission name="user:delete:*"><li><a href="">删除</a></li></shiro:hasPermission><shiro:hasPermission name="user:update:*"><li><a href="">修改</a></li></shiro:hasPermission><shiro:hasPermission name="user:find:*"><li><a href="">查询</a></li></shiro:hasPermission></ul></shiro:hasRole><shiro:hasRole name="admin"><li><a href="">商品管理</a></li><li><a href="">订单管理</a></li><li><a href="">物流管理</a></li></shiro:hasRole></ul>
</body>
</html>

6.5.shiro整合springboot之授权数据的数据库获取

数据库表设计

准备五张表,两张中间表

sql语句

/*
SQLyog Ultimate v12.09 (64 bit)
MySQL - 8.0.11 : Database - shiro
*********************************************************************
*//*!40101 SET NAMES utf8 */;/*!40101 SET SQL_MODE=''*/;/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`shiro` /*!40100 DEFAULT CHARACTER SET utf8 */;USE `shiro`;/*Table structure for table `pers` */DROP TABLE IF EXISTS `pers`;CREATE TABLE `pers` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(40) DEFAULT NULL,`url` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;/*Data for the table `pers` */insert  into `pers`(`id`,`name`,`url`) values (1,'user:*:*',NULL),(2,'product:*:*',NULL),(3,'order:*:*',NULL);/*Table structure for table `role` */DROP TABLE IF EXISTS `role`;CREATE TABLE `role` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(40) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;/*Data for the table `role` */insert  into `role`(`id`,`name`) values (1,'user'),(2,'admin'),(3,'produce');/*Table structure for table `role_perms` */DROP TABLE IF EXISTS `role_perms`;CREATE TABLE `role_perms` (`id` int(6) NOT NULL AUTO_INCREMENT,`roleid` int(6) DEFAULT NULL,`permsid` int(6) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;/*Data for the table `role_perms` */insert  into `role_perms`(`id`,`roleid`,`permsid`) values (1,1,1),(2,1,2),(3,2,1),(4,3,2),(5,2,3);/*Table structure for table `user` */DROP TABLE IF EXISTS `user`;CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`password` varchar(40) DEFAULT NULL,`username` varchar(10) DEFAULT NULL,`salt` varchar(20) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;/*Data for the table `user` */insert  into `user`(`id`,`password`,`username`,`salt`) values (1,'aa337c0f7ba12939db8998b3a4b15eb3','ryw','pLEJ3#1P'),(2,'136c2118bc6716fbd8bdf59df815956f','hzw01','dhh8e1RN');/*Table structure for table `user_role` */DROP TABLE IF EXISTS `user_role`;CREATE TABLE `user_role` (`id` int(11) NOT NULL AUTO_INCREMENT,`userid` int(6) DEFAULT NULL,`roleid` int(6) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;/*Data for the table `user_role` */insert  into `user_role`(`id`,`userid`,`roleid`) values (1,1,1),(2,2,2),(3,2,3),(4,2,1);/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

entry实体类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class Pers {private Integer id;private String name;
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;import java.util.List;@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class Role {private Integer id;private String name;private List<Pers> pers;
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;import java.util.List;@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class User {private int id;private String username;private String password;private String salt;private List<Role> roles;
}

UserDao接口

import com.hzw.entry.Pers;
import com.hzw.entry.User;
import org.apache.ibatis.annotations.Mapper;import java.util.List;@Mapper
public interface UserDao {//保存void save(User user);//根据用户名查询业务的方法User findByUserName(String username);//根据用户名查询所有角色User findRolesByUserName(String username);//根据角色id查询权限集合List<Pers> findPermsByRoleId(Integer id);
}

mapper配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hzw.dao.UserDao"><insert id="save" parameterType="com.hzw.entry.User" useGeneratedKeys="true" keyProperty="id">insert into user(username,password,salt) values (#{username},#{password},#{salt})</insert><select id="findByUserName" resultType="com.hzw.entry.User" parameterType="String">select id,username,password,salt from userwhere username=#{username}</select><resultMap id="userMap" type="com.hzw.entry.User"><id column="uid" property="id"></id><result column="username" property="username"/><collection property="roles" javaType="list" ofType="com.hzw.entry.Role"><id column="rid" property="id"></id><result column="name" property="name"></result></collection></resultMap><select id="findRolesByUserName" parameterType="String" resultMap="userMap">SELECT u.`id` uid,u.`username`,r.`id` rid,r.`name`FROM USER uLEFT JOIN `user_role` urON u.`id`=ur.`userid`LEFT JOIN role rON ur.`roleid`=r.`id`WHERE u.`username`=#{username}</select><select id="findPermsByRoleId" resultType="com.hzw.entry.Pers">SELECT p.id,p.name,p.url,r.`name`FROM role rLEFT JOIN role_perms rpON r.id=rp.roleidLEFT JOIN pers pON p.id=rp.permsidWHERE r.id=#{id}</select>
</mapper>

配置类 application.properties

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hzw.dao.UserDao"><insert id="save" parameterType="com.hzw.entry.User" useGeneratedKeys="true" keyProperty="id">insert into user(username,password,salt) values (#{username},#{password},#{salt})</insert><select id="findByUserName" resultType="com.hzw.entry.User" parameterType="String">select id,username,password,salt from userwhere username=#{username}</select><resultMap id="userMap" type="com.hzw.entry.User"><id column="uid" property="id"></id><result column="username" property="username"/><collection property="roles" javaType="list" ofType="com.hzw.entry.Role"><id column="rid" property="id"></id><result column="name" property="name"></result></collection></resultMap><select id="findRolesByUserName" parameterType="String" resultMap="userMap">SELECT u.`id` uid,u.`username`,r.`id` rid,r.`name`FROM USER uLEFT JOIN `user_role` urON u.`id`=ur.`userid`LEFT JOIN role rON ur.`roleid`=r.`id`WHERE u.`username`=#{username}</select><select id="findPermsByRoleId" resultType="com.hzw.entry.Pers">SELECT p.id,p.name,p.url,r.`name`FROM role rLEFT JOIN role_perms rpON r.id=rp.roleidLEFT JOIN pers pON p.id=rp.permsidWHERE r.id=#{id}</select>
</mapper>

jsp

index.jsp 首页

<%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<!doctype html>
<head><meta charset="UTF-8"><meta name="viewport"content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>首页</title>
</head>
<body>
<h1>系统主页</h1>
<a href="${pageContext.request.contextPath}/user/logout">退出登录</a>
<ul style="list-style: none"><%--角色授权--%><shiro:hasRole name="user"><li><a href="">用户管理</a></li><ul><%--资源授权--%><shiro:hasPermission name="user:add:*"><li><a href="">添加</a></li></shiro:hasPermission><shiro:hasPermission name="user:delete:*"><li><a href="">删除</a></li></shiro:hasPermission><shiro:hasPermission name="user:update:*"><li><a href="">修改</a></li></shiro:hasPermission><shiro:hasPermission name="order:find:*"><li><a href="">查询</a></li></shiro:hasPermission></ul></shiro:hasRole><shiro:hasRole name="admin"><li><a href="">商品管理</a></li><li><a href="">订单管理</a></li><li><a href="">物流管理</a></li></shiro:hasRole></ul>
</body>
</html>

login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>登录</title>
</head>
<body>
<h2>VIP用户登录</h2>
<form action="${pageContext.request.contextPath}/user/login" method="post">用户名:<input type="text" name="username"><br/>密码:  <input type="password" name="password" ><br/><input type="submit" value="登录">
</form>
</body>
</html>

register.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body>
<h1>用户注册</h1>
<form action="${pageContext.request.contextPath}/user/register" method="post">用户名:<input type="text" name="username"><br/>密码:  <input type="text" name="password" ><br/><input type="submit" value="用户注册"></form>
</body>
</html>

Service接口和实现类

import java.util.List;
public interface UserService {//注册用户方法void register(User user);//根据用户名查询业务的方法User findByUserName(String username);//根据用户名查询所有角色User findRolesByUserName(String username);//根据角色id查询权限集合List<Pers> findPermsByRoleId(Integer id);
}
package com.hzw.service.impl;
import com.hzw.dao.UserDao;
import com.hzw.entry.Pers;
import com.hzw.entry.User;
import com.hzw.service.UserService;
import com.hzw.utils.SaltUtils;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service("userService")
@Transactional
public class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao;@Overridepublic void register(User user) {//1.生成saltString salt = SaltUtils.getSalt(8);System.out.println(salt);//2.保存user.setSalt(salt);//3.明文密码:md5+salt+hashMd5Hash md5Hash = new Md5Hash(user.getPassword(),salt,1024);user.setPassword(md5Hash.toHex());System.out.println(md5Hash);userDao.save(user);}@Overridepublic User findByUserName(String username) {return userDao.findByUserName(username);}@Overridepublic User findRolesByUserName(String username) {return userDao.findRolesByUserName(username);}@Overridepublic List<Pers> findPermsByRoleId(Integer id) {return userDao.findPermsByRoleId(id);}}

自定义Shiro

package com.hzw.shiro;
import com.hzw.entry.Pers;
import com.hzw.entry.Role;
import com.hzw.entry.User;
import com.hzw.service.UserService;
import com.hzw.utils.AppliactionContextUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;import java.util.List;public class CustomerRealm extends AuthorizingRealm {@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {//获取身份信息String primaryPrincipal = (String) principal.getPrimaryPrincipal();System.out.println("调用授权验证:"+primaryPrincipal);//根据主身份获取角色和权限信息UserService userService =(UserService)AppliactionContextUtils.getBean("userService");User user = userService.findRolesByUserName(primaryPrincipal);//授权信息if (user.getRoles()!=null){SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();for (Role role : user.getRoles()) {simpleAuthorizationInfo.addRole(role.getName());//权限信息List<Pers> perms = userService.findPermsByRoleId(role.getId());if (!CollectionUtils.isEmpty(perms)){for (Pers perm : perms) {simpleAuthorizationInfo.addStringPermission(perm.getName());}}}return simpleAuthorizationInfo;}return null;}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {System.out.println("================");//获取身份信息String principal = (String)token.getPrincipal();UserService userService =(UserService)AppliactionContextUtils.getBean("userService");User user = userService.findByUserName(principal);System.out.println(principal);if (!ObjectUtils.isEmpty(user)){return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),ByteSource.Util.bytes(user.getSalt()),this.getName());}return null;}
}

shiro拦截器

package com.hzw.config;import com.hzw.shiro.CustomerRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.HashMap;@Configuration
public class ShiroConfig  {//1.创建shiroFilter所有拦截请求@Bean(name = "shiroFilterFactoryBean")public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();//给filter设置安全管理器shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);HashMap<String, String> map = new HashMap<>();map.put("/user/login","anon");         //配置系统公共资源map.put("/user/register","anon");         //配置系统公共资源map.put("order/save","anon");map.put("/register.jsp","anon");         //配置系统公共资源//配置系统受限资源map.put("/**","authc");   //authc 请求这个资源要认证和授权//默认认证界面路径shiroFilterFactoryBean.setLoginUrl("/login.jsp");shiroFilterFactoryBean.setFilterChainDefinitionMap(map);return shiroFilterFactoryBean;}//2.创建安全管理器@Beanpublic DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm){DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();//给安全管理器设置defaultWebSecurityManager.setRealm(realm);return defaultWebSecurityManager;}//3.创建自定义realm@Beanpublic Realm realm(){CustomerRealm customerRealm = new CustomerRealm();//hash凭证校验匹配器HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();//设置加密算法为MD5credentialsMatcher.setHashAlgorithmName("MD5");//设置散列次数credentialsMatcher.setHashIterations(1024);customerRealm.setCredentialsMatcher(credentialsMatcher);return customerRealm;}}

controller

package com.hzw.controller;
import com.hzw.entry.User;
import com.hzw.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("user")
public class UserController {@Autowiredprivate UserService userService;@RequestMapping("register")public String register(User user){try {userService.register(user);return "redirect:/login.jsp";}catch (Exception e){e.printStackTrace();return "redirect:/register.jsp";}}/*** 退出登录* @return*/@RequestMapping("logout")public String logout(){Subject subject = SecurityUtils.getSubject();subject.logout();return "redirect:/login.jsp";}/*** 处理身份认证* @param username* @param password* @return*/@RequestMapping("/login")public String login(String username,String password){//获取主题对象Subject subject = SecurityUtils.getSubject();try {subject.login(new UsernamePasswordToken(username,password));return "redirect:/index.jsp";}catch (UnknownAccountException e){e.getStackTrace();System.out.println("用户名错误");}catch (IncorrectCredentialsException e){e.getStackTrace();System.out.println("密码错误");}return "redirect:/login.jsp";}
}

utils工具

获取随机盐

package com.hzw.utils;import java.util.Random;public class SaltUtils {public static String getSalt(int n){char[] chars="ABCDEFGHIJKLMNOPORSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890!@#&*()".toCharArray();StringBuilder stringBuilder = new StringBuilder();for (int i = 0; i <n ; i++) {char aChar=chars[new Random().nextInt(chars.length)];stringBuilder.append(aChar);}return stringBuilder.toString();}public static void main(String[] args) {String salt = getSalt(8);System.out.println(salt);}}

通过bean名字获取bean对象

package com.hzw.utils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class AppliactionContextUtils implements ApplicationContextAware {private static ApplicationContext context;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.context=applicationContext;}//根据bean名字获取工厂指定bean对象public  static Object getBean(String beanName){Object bean = context.getBean(beanName);return bean;}
}

测试

user 用户管理的查询操作  需要有order.*.*资源权限

测试截图  user没有查询的操作

admin 拥有全部操作权限

6.8使用CacheManager
1.Cache作用

Cache缓存:计算机内存中一段数据内存条
作用:用来减轻DB的访问压力,从而提高系统的查询效率
流程:

2.使用shiro中默认EhCache实现缓存

开启依赖

 <!--引入shiro和ehcache--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-ehcache</artifactId><version>1.3.2</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>4.3.7.RELEASE</version></dependency>

2.开启cache管理

//3.创建自定义realm@Beanpublic Realm realm(){CustomerRealm customerRealm = new CustomerRealm();//hash凭证校验匹配器HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();//设置加密算法为MD5credentialsMatcher.setHashAlgorithmName("MD5");//设置散列次数credentialsMatcher.setHashIterations(1024);customerRealm.setCredentialsMatcher(credentialsMatcher);//开启缓存管理customerRealm.setCacheManager(new EhCacheManager());customerRealm.setCachingEnabled(true);  //开启全局缓存customerRealm.setAuthenticationCachingEnabled(true); //开启认证缓存customerRealm.setAuthenticationCacheName("authenticationCache");customerRealm.setAuthorizationCachingEnabled(true); //开启授权缓存customerRealm.setAuthorizationCacheName("authorizationCache");return customerRealm;}

6.9Shiro整合springboot缓存之Redis

1.导入data-redis依赖

  <!--redis--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

2.自定义redis缓存实现

package com.hzw.shiro.cache;import com.hzw.utils.AppliactionContextUtils;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.util.Collection;
import java.util.Set;//自定义redis缓存实现
public class RedisCache<k,v> implements Cache<k,v> {private String cacheName;public RedisCache(){}public RedisCache(String cacheName) {this.cacheName = cacheName;}@Overridepublic v get(k k) throws CacheException {System.out.println("get key:"+k);return(v) getRedisTemplate().opsForHash().get(this.cacheName,k.toString());}@Overridepublic v put(k k, v v) throws CacheException {System.out.println("put key:"+k);System.out.println("put value:"+v);getRedisTemplate().opsForHash().put(this.cacheName,k.toString(),v);return null;}@Overridepublic v remove(k k) throws CacheException {return (v) getRedisTemplate().opsForHash().delete(this.cacheName,k.toString());}@Overridepublic void clear() throws CacheException {getRedisTemplate().delete(this.cacheName);}@Overridepublic int size() {return getRedisTemplate().opsForHash().size(this.cacheName).intValue();}@Overridepublic Set<k> keys() {return getRedisTemplate().opsForHash().keys(this.cacheName);}@Overridepublic Collection<v> values() {return getRedisTemplate().opsForHash().values(this.cacheName);}private static RedisTemplate getRedisTemplate(){RedisTemplate redisTemplate = (RedisTemplate)AppliactionContextUtils.getBean("redisTemplate");redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());return redisTemplate;}
}

3.自定义RedisCacheManager 实现CacheManager

package com.hzw.shiro.cache;import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
public class RedisCacheManager implements CacheManager {//参数1:认证或者是授权缓存的统一名称@Overridepublic <K, V> Cache<K, V> getCache(String cacheName) throws CacheException {System.out.println(cacheName);return new RedisCache<K,V>(cacheName);}
}

4.在shiroconfig 将EnCache修改为自定义RedisCacheManager开启缓存管理

 //3.创建自定义realm@Beanpublic Realm realm(){CustomerRealm customerRealm = new CustomerRealm();//hash凭证校验匹配器HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();//设置加密算法为MD5credentialsMatcher.setHashAlgorithmName("MD5");//设置散列次数credentialsMatcher.setHashIterations(1024);customerRealm.setCredentialsMatcher(credentialsMatcher);//开启缓存管理customerRealm.setCacheManager(new RedisCacheManager());customerRealm.setCachingEnabled(true);  //开启全局缓存customerRealm.setAuthenticationCachingEnabled(true); //开启认证缓存customerRealm.setAuthenticationCacheName("authenticationCache");customerRealm.setAuthorizationCachingEnabled(true); //开启授权缓存customerRealm.setAuthorizationCacheName("authorizationCache");return customerRealm;}

5.随机盐序列化 自定义类 实现ByteSource

package com.hzw.shiro;import org.apache.shiro.codec.Base64;
import org.apache.shiro.codec.CodecSupport;
import org.apache.shiro.codec.Hex;
import org.apache.shiro.util.ByteSource;
import java.io.File;
import java.io.InputStream;
import java.io.Serializable;
import java.util.Arrays;
//自定义随机盐转化
public class MyBateSource implements ByteSource,Serializable{private byte[] bytes;private String cachedHex;private String cachedBase64;public MyBateSource(){}public MyBateSource(byte[] bytes) {this.bytes = bytes;}public MyBateSource(char[] chars) {this.bytes = CodecSupport.toBytes(chars);}public MyBateSource(String string) {this.bytes = CodecSupport.toBytes(string);}public MyBateSource(ByteSource source) {this.bytes = source.getBytes();}public MyBateSource(File file) {this.bytes = (new MyBateSource.BytesHelper()).getBytes(file);}public MyBateSource(InputStream stream) {this.bytes = (new MyBateSource.BytesHelper()).getBytes(stream);}public static boolean isCompatible(Object o) {return o instanceof byte[] || o instanceof char[] || o instanceof String || o instanceof ByteSource || o instanceof File || o instanceof InputStream;}public byte[] getBytes() {return this.bytes;}public boolean isEmpty() {return this.bytes == null || this.bytes.length == 0;}public String toHex() {if (this.cachedHex == null) {this.cachedHex = Hex.encodeToString(this.getBytes());}return this.cachedHex;}public String toBase64() {if (this.cachedBase64 == null) {this.cachedBase64 = Base64.encodeToString(this.getBytes());}return this.cachedBase64;}public String toString() {return this.toBase64();}public int hashCode() {return this.bytes != null && this.bytes.length != 0 ? Arrays.hashCode(this.bytes) : 0;}public boolean equals(Object o) {if (o == this) {return true;} else if (o instanceof ByteSource) {ByteSource bs = (ByteSource)o;return Arrays.equals(this.getBytes(), bs.getBytes());} else {return false;}}private static final class BytesHelper extends CodecSupport {private BytesHelper() {}public byte[] getBytes(File file) {return this.toBytes(file);}public byte[] getBytes(InputStream stream) {return this.toBytes(stream);}}
}

5.CustomerRealm  new MyBateSource(user.getSalt())

@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {System.out.println("================");//获取身份信息String principal = (String)token.getPrincipal();UserService userService =(UserService)AppliactionContextUtils.getBean("userService");User user = userService.findByUserName(principal);System.out.println(principal);if (!ObjectUtils.isEmpty(user)){return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),new MyBateSource(user.getSalt()),this.getName());}return null;}
}

6.各实体类都需要实现序列化

Pers

Role

User

测试结果可以看出登录账号从redis里取shiro缓存信息

7.Shiro整合springboot之thymeleaf权限控制
1.引入扩展依赖

Shiro框架学习笔记、整合Springboot、redis缓存相关推荐

  1. SpringBoot学习笔记(16)----SpringBoot整合Swagger2

    Swagger 是一个规范和完整的框架,用于生成,描述,调用和可视化RESTful风格的web服务 http://swagger.io Springfox的前身是swagger-springmvc,是 ...

  2. 27Vert.X框架学习笔记

    vert.x框架学习笔记 文章目录 1 Vert.x简明介绍 1.1 Vert.x能干什么 1.2 Vert.x快速体验 1.3 Vert.x的简单介绍 1.4 Vert.x的一些优势 1.4.1 异 ...

  3. kratos mysql_kratos微服务框架学习笔记一(kratos-demo)

    本文将为您描述kratos微服务框架学习笔记一(kratos-demo),教程操作步骤: 目录 kratos微服务框架学习笔记一(kratos-demo) kratos本体 demo kratos微服 ...

  4. SpringMVC框架--学习笔记(上)

    1.SpringMVC入门程序: (1)导入jar包:spring核心jar包.spring-webmvc整合Jar包 (2)配置前端控制器:web.xml文件中 <?xml version=& ...

  5. mybatis框架--学习笔记(下)

    上篇:mybatis框架--学习笔记(上):https://blog.csdn.net/a745233700/article/details/81034021 8.高级映射: (1)一对一查询: ①使 ...

  6. Spring Boot 框架学习笔记(五)( SpringSecurity安全框架 )

    Spring Boot 框架学习笔记(五) SpringSecurity安全框架 概述 作用 开发示例: 1. 新建项目 2. 引入依赖 3. 编写`SecurityConfig`类,实现认证,授权, ...

  7. JeeSite 框架学习笔记

    JeeSite 框架学习笔记 目录 JeeSite 框架学习笔记 一.全局配置 1. 获取 Resource资源实际路径 DefaultResourceLoader 2. 配置前端 js css 二. ...

  8. mybatis框架--学习笔记(上)

    使用JDBC操作数据库的问题总结: (1)数据库连接,使用时创建,不使用时立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响数据库性能. 设想:使用数据库连接池管理数据库连接. (2) ...

  9. SpringBoot学习笔记(4)----SpringBoot中freemarker、thymeleaf的使用

    1. freemarker引擎的使用 如果你使用的是idea或者eclipse中安装了sts插件,那么在新建项目时就可以直接指定试图模板 如图: 勾选freeMarker,此时springboot项目 ...

最新文章

  1. 万物生长,万物互联的时代来了
  2. 企业网络推广方案教网站优化新手更合理地处理过期页面
  3. /usr/bin/install: cannot create regular file ‘/usr/local/lib/libpcre.so.1.2.13‘: Permission denied
  4. java基础IO BIO、NIO、AIO的区别
  5. Go 中string和int类型相互转换
  6. P2168 [NOI2015] 荷马史诗(哈夫曼编码树)
  7. 堆排序python代码实现_python实现堆排序
  8. 【HDU - 5012】Dice(模拟,bfs)
  9. zynq的emio和axi_【ZYNQ7000学习之旅 - 01】EMIO练习
  10. Dev c++一些调试方法
  11. 死锁(Deadlock)
  12. 疫情政务问答助手算法冠军开源
  13. 配置codeblocks 的养眼colour theme ;鼠标颜色与型状配置,界面汉化,以及调试入门
  14. Maven Dependency设置,详解!
  15. 本特利振动探头177230-01-01-CN
  16. 小学计算机京剧脸谱教案,[热门]《戏曲脸谱》小学美术教学案例
  17. 老A:抖音爆火的“弹幕互动游戏”是什么?该如何搭建直播间?
  18. mining.subscribe与initiate_stratum函数
  19. ROS2使用OpenCV基础
  20. java-EasyExcel导出excel设置单元格为文本格式(含代码)

热门文章

  1. C语言那些事之脉冲丢包率检测
  2. [BZOJ 3653] 谈笑风生
  3. Aquaculture Equipment 水产养殖设备谷歌Google搜索量和海外市场竞争度分析
  4. 高德打车通用可编排订单状态机引擎设计
  5. eve手游php,[Murky Army]EVE无烬星河PVP入门————小队战战术及队伍配置(
  6. 微型计算机48MHz辐射超,EMI辐射测试超标 求高手指点
  7. 理解COM的线程套件(转)
  8. 让logo设计更有设计感的几个方法
  9. #JAVA# JAVA简易版计算器GUI编程练习
  10. 程序员所使用的各种软件分享及破解