没有网站怎么做CPC北京网站优化策略

diannao/2026/1/24 3:00:45/文章来源:
没有网站怎么做CPC,北京网站优化策略,wordpress主题php7,建网站_网站内容怎么做Shiro 实战教程 1.权限的管理 1.1 什么是权限管理 ​ 基本上涉及到用户参与的系统都要进行权限管理#xff0c;权限管理属于系统安全的范畴#xff0c;权限管理实现对用户访问系统的控制#xff0c;按照安全规则或者安全策略控制用户可以访问而且只能访问自己被授权的资源…Shiro 实战教程 1.权限的管理 1.1 什么是权限管理 ​ 基本上涉及到用户参与的系统都要进行权限管理权限管理属于系统安全的范畴权限管理实现对用户访问系统的控制按照安全规则或者安全策略控制用户可以访问而且只能访问自己被授权的资源。 ​ 权限管理包括用户身份认证和授权两部分简称认证授权。对于需要访问控制的资源用户首先经过身份认证认证通过后用户具有该资源的访问权限方可访问。 1.2 什么是身份认证 身份认证就是判断一个用户是否为合法用户的处理过程。最常用的简单身份认证方式是系统通过核对用户输入的用户名和口令看其是否与系统中存储的该用户的用户名和口令一致来判断用户身份是否正确。对于采用指纹等系统则出示指纹对于硬件Key等刷卡系统则需要刷卡。 1.3 什么是授权 授权即访问控制控制谁能访问哪些资源。主体进行身份认证后需要分配权限方可访问系统的资源对于某些资源没有权限是无法访问的 2.什么是shiro Apache Shiro™ is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management. With Shiro’s easy-to-understand API, you can quickly and easily secure any application – from the smallest mobile applications to the largest web and enterprise applications. Shiro 是一个功能强大且易于使用的Java安全框架它执行身份验证、授权、加密和会话管理。使用Shiro易于理解的API您可以快速轻松地保护任何应用程序—从最小的移动应用程序到最大的web和企业应用程序。 Shiro是apache旗下一个开源框架它将软件系统的安全认证相关的功能抽取出来实现用户身份认证权限授权、加密、会话管理等功能组成了一个通用的安全认证框架。 3.shiro的核心架构 3.1 Subject Subject即主体外部应用与subject进行交互subject记录了当前操作用户将用户的概念理解为当前操作的主体可能是一个通过浏览器请求的用户也可能是一个运行的程序。 Subject在shiro中是一个接口接口中定义了很多认证授权相关的方法外部程序通过subject进行认证授权而subject是通过SecurityManager安全管理器进行认证授权 3.2 SecurityManager(安全管理器最核心) SecurityManager即安全管理器它是shiro的核心负责对所有的subject进行安全管理。通过SecurityManager可以完成subject的认证、授权等实质上SecurityManager是通过Authenticator进行认证通过Authorizer进行授权通过SessionManager进行会话管理等。 SecurityManager是一个接口继承了Authenticator, Authorizer, SessionManager这三个接口。 3.3 Authenticator Authenticator即认证器对用户身份进行认证Authenticator是一个接口shiro提供ModularRealmAuthenticator实现类通过ModularRealmAuthenticator基本上可以满足大多数需求也可以自定义认证器。 3.4 Authorizer Authorizer即授权器用户通过认证器认证通过在访问功能时需要通过授权器判断用户是否有此功能的操作权限。 3.5 Realm Realm即领域相当于datasource数据源securityManager进行安全认证需要通过Realm获取用户权限数据比如如果用户身份数据在数据库那么realm就需要从数据库获取用户身份信息。 ​ 注意不要把realm理解成只是从数据源取数据在realm中还有认证授权校验的相关的代码。 3.6 SessionManager sessionManager即会话管理shiro框架定义了一套会话管理它不依赖web容器的session所以shiro可以使用在非web应用上也可以将分布式应用的会话集中在一点管理此特性可使它实现单点登录。 3.7 SessionDAO SessionDAO即会话dao是对session会话操作的一套接口比如要将session存储到数据库可以通过jdbc将会话存储到数据库。 3.8 CacheManager CacheManager即缓存管理将用户权限数据存储在缓存这样可以提高性能。 3.9 Cryptography ​ Cryptography即密码管理shiro提供了一套加密/解密的组件方便开发。比如提供常用的散列、加/解密等功能。 4. shiro中的认证 4.1 认证 身份认证就是判断一个用户是否为合法用户的处理过程。最常用的简单身份认证方式是系统通过核对用户输入的用户名和口令看其是否与系统中存储的该用户的用户名和口令一致来判断用户身份是否正确。 4.2 shiro中认证的关键对象 Subject主体 访问系统的用户主体可以是用户、程序等进行认证的都称为主体 Principal身份信息 是主体subject进行身份认证的标识标识必须具有唯一性如用户名、手机号、邮箱地址等一个主体可以有多个身份但是必须有一个主身份Primary Principal。 credential凭证信息 是只有主体自己知道的安全信息如密码、证书等。 4.3 认证流程 4.4 认证的开发 1. 创建项目并引入依赖 dependencygroupIdorg.apache.shiro/groupIdartifactIdshiro-core/artifactIdversion1.5.3/version /dependency2. 引入shiro配置文件并加入如下配置 配置文件.ini 结尾文件复杂数据格式 用来学习shiro书写我们系统中相关权限数据。整合时用不到 [users] xiaochen123 zhangsan456 等于在系统中定义了两个合法用户3.开发认证代码 public class TestAuthenticator {public static void main(String[] args) {//创建securityManager安全管理器对象DefaultSecurityManager defaultSecurityManager new DefaultSecurityManager();//给安全管理器设置realmdefaultSecurityManager.setRealm(new IniRealm(classpath:shiro.ini));//给全局安全工具类设置安全管理器SecurityUtils.setSecurityManager(defaultSecurityManager);//获取主体对象Subject subject SecurityUtils.getSubject();//创建token令牌UsernamePasswordToken token new UsernamePasswordToken(xiaochen1, 123);try {subject.login(token);//用户登录 没有返回值 认证通过没有任何异常否则会抛出异常System.out.println(登录成功~~);} catch (UnknownAccountException e) {e.printStackTrace();System.out.println(用户名错误!!);}catch (IncorrectCredentialsException e){e.printStackTrace();System.out.println(密码错误!!!);}} }DisabledAccountException帐号被禁用 LockedAccountException帐号被锁定 ExcessiveAttemptsException登录失败次数过多 ExpiredCredentialsException凭证过期等 上边开发认证代码源码分析得到结论封装非常深 1.最终执行用户名比较 SimpleAccountRealm 中doGetAuthenticationInfo 在这个方法中完成用户名校验 2.最终密码校验在AuthenticatingRealm中 assertCredentialsMatch public class SimpleAccountRealm extends AuthorizingRealm {总结 ​ AuthenticatingRealm认证realm doGetAuthenticationInfo ​ AuthorizingRealm 授权realm doGetAuthorizationInfo 4.5 自定义Realm 上边的程序使用的是Shiro自带的IniRealmIniRealm从ini配置文件中读取用户的信息大部分情况下需要从系统的数据库中读取用户信息所以需要自定义realm。 1.shiro提供的Realm 2.根据认证源码认证使用的是SimpleAccountRealm SimpleAccountRealm的部分源码中有两个方法一个是 认证 一个是 授权, public class SimpleAccountRealm extends AuthorizingRealm {//.......省略protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {UsernamePasswordToken upToken (UsernamePasswordToken) token;SimpleAccount account getUser(upToken.getUsername());if (account ! null) {if (account.isLocked()) {throw new LockedAccountException(Account [ account ] is locked.);}if (account.isCredentialsExpired()) {String msg The credentials for account [ account ] are expired;throw new ExpiredCredentialsException(msg);}}return account;}//授权protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {String username getUsername(principals);USERS_LOCK.readLock().lock();try {return this.users.get(username);} finally {USERS_LOCK.readLock().unlock();}} }3.自定义realm //自定义realm实现将认证/授权数据的来源转为数据库的实现 public class CustomerRealm extends AuthorizingRealm {//授权方法Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {return null;}//认证方法Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {String principal (String) token.getPrincipal();System.out.println(principal);//能够获取到tocken中的用户名if(xiaochen.equals(principal)){//参数1返回数据库中正确的用户名 参数2返回数据库中正确的密码 参数3提供当前realm的名字 this.getName(); return new SimpleAuthenticationInfo(principal,123,this.getName());}return null;} }4.使用自定义Realm认证 public class TestAuthenticatorCusttomerRealm {public static void main(String[] args) {//创建securityManagerDefaultSecurityManager defaultSecurityManager new DefaultSecurityManager();//IniRealm realm new IniRealm(classpath:shiro.ini);//设置为自定义realm获取认证数据defaultSecurityManager.setRealm(new CustomerRealm());//将安装工具类中设置默认安全管理器SecurityUtils.setSecurityManager(defaultSecurityManager);//获取主体对象Subject subject SecurityUtils.getSubject();//创建token令牌UsernamePasswordToken token new UsernamePasswordToken(xiaochen, 123);try {subject.login(token);//用户登录System.out.println(登录成功~~);} catch (UnknownAccountException e) {e.printStackTrace();System.out.println(用户名错误!!);}catch (IncorrectCredentialsException e){e.printStackTrace();System.out.println(密码错误!!!);}} }4.6 使用MD5(加密)和Salt(随机盐) MD5算法作用一般用来加密或者签名校验和 ​ 特点算法不可逆如果内容相同无论执行多少次md5生成结果始终是一致的 ​ 123——》feas122121221ddd… 网上很多md5解密工具使用的是穷举算法md5只要值一样执行多少次结果都是一样网上的将常用的密码都生成好了让你去比较。 ​ 生成结果始终是一个16进制32位长度字符串。 执行流程 注册时加盐和密码进行拼接之后存入数据库并且把盐也存入到数据库中用户再次登录时先拿着用户名去数据库查找盐把盐和密码拼接之后再去和数据库中密码比较并且盐的拼接要和业务层Service的拼接顺序一致。 有人攻破数据库会看到盐还不安全不能因为防盗门还有可能被盗就不按门。 md5作为签名的应用场景如何比较a.txt和b.txt这两个文件中的内容是否一致md5可以对文件的内容进行校验如果生成的值一样这两个文件一定是一样的。 例下载文件时tomcat.zip tomcat.md5点进去可以看到一串字符当自己下载完成后可以用md5与之比较一致一定下载正确。 实际应用是将盐和散列后的值存在数据库中自动realm从数据库取出盐和加密后的值由shiro完成密码校验。 //MD5 public class TestShiroMD5 {public static void main(String[] args) {/*Md5Hash md5Hashnew Md5Hash();md5Hash.setBytes(123.getBytes());String s md5Hash.toHex();System.out.println(s);*///使用MD5Md5Hash md5Hash new Md5Hash(123);System.out.println(md5Hash.toHex());//使用MD5saltMd5Hash md5Hash1 new Md5Hash(123, X0*7ps);System.out.println(md5Hash1.toHex());//使用MD5salthash散列 散列次数越多越均匀Md5Hash md5Hash2 new Md5Hash(123, X0*7ps, 1024);System.out.println(md5Hash2.toHex());} }1.自定义md5salt的realm public class CustomerRealm extends AuthorizingRealm {//授权方法Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {return null;}//认证方法Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {String principal (String) token.getPrincipal();if(xiaochen.equals(principal)){String password 3c88b338102c1a343bcb88cd3878758e;String salt Q4F%; //参数1数据库用户名 2数据库md5salt之后的密码 3注册时 的随机盐 4realm的名字return new SimpleAuthenticationInfo(principal,password, ByteSource.Util.bytes(salt),this.getName());}return null;} 2.使用md5 salt 认证 public class TestAuthenticatorCusttomerRealm {public static void main(String[] args) {//创建安全管理器DefaultSecurityManager defaultSecurityManager new DefaultSecurityManager();//IniRealm realm new IniRealm(classpath:shiro.ini);//设置为自定义realm获取认证数据CustomerRealm realm new CustomerRealm();//设置realm使用hash凭证匹配器HashedCredentialsMatcher credentialsMatcher new HashedCredentialsMatcher();//使用算法credentialsMatcher.setHashAlgorithmName(MD5);//散列次数credentialsMatcher.setHashIterations(1024);//设置散列次数realm.setCredentialsMatcher(credentialsMatcher);defaultSecurityManager.setRealm(realm);//将安装工具类中设置默认安全管理器SecurityUtils.setSecurityManager(defaultSecurityManager);//通过安全工具类获得subjectSubject subject SecurityUtils.getSubject();//创建token令牌UsernamePasswordToken token new UsernamePasswordToken(xiaochen, 123);try {subject.login(token);//用户登录System.out.println(登录成功~~);} catch (UnknownAccountException e) {e.printStackTrace();System.out.println(用户名错误!!);}catch (IncorrectCredentialsException e){e.printStackTrace();System.out.println(密码错误!!!);}} } 5. shiro中的授权 5.1 授权 授权即访问控制控制谁能访问哪些资源。主体进行身份认证后需要分配权限方可访问系统的资源对于某些资源没有权限是无法访问的。 5.2 关键对象 授权可简单理解为who对what(which)进行How操作 Who即主体Subject主体需要访问系统中的资源。 What即资源Resource)如系统菜单、页面、按钮、类方法、系统商品信息等。资源包括资源类型和资源实例比如商品信息为资源类型类型为t01的商品为资源实例编号为001的商品信息也属于资源实例。 How权限/许可Permission)规定了主体对资源的操作许可权限离开资源没有意义如用户查询权限、用户添加权限、某个类方法的调用权限、编号为001用户的修改权限等通过权限可知主体对哪些资源都有哪些操作许可。 5.3 授权流程 5.4 授权方式 基于角色的访问控制 RBAC基于角色的访问控制Role-Based Access Control是以角色为中心进行访问控制 if(subject.hasRole(admin)){ //伪代码//操作什么资源 } 基于资源的访问控制 RBAC基于资源的访问控制Resource-Based Access Control是以资源为中心进行访问控制 if(subject.isPermission(user:update:01)){ //资源实例//对01用户进行修改 } if(subject.isPermission(user:update:*)){ //资源类型//对01用户进行修改 } 5.5 权限字符串 ​ 权限字符串的规则是资源标识符操作资源实例标识符意思是对哪个资源的哪个实例具有什么操作“:”是资源/操作/实例的分割符权限字符串也可以使用*通配符。 例子 用户创建权限user:create或user:create:*用户修改实例001的权限user:update:001用户实例001的所有权限user:*001 5.6 shiro中授权编程实现方式 编程式 Subject subject SecurityUtils.getSubject(); if(subject.hasRole(“admin”)) {//有权限 } else {//无权限 } 注解式 RequiresRoles(admin) public void hello() {//有权限 } 标签式、 JSP/GSP 标签在JSP/GSP 页面通过相应的标签完成 shiro:hasRole nameadmin!— 有权限— /shiro:hasRole 注意: Thymeleaf 中使用shiro需要额外集成! 5.7 开发授权 1.realm的实现 public class CustomerRealm extends AuthorizingRealm {//授权方法Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {String primaryPrincipal (String) principals.getPrimaryPrincipal();System.out.println(身份信息 primaryPrincipal);//根据身份信息 用户名 获取当前用户的角色信息以及权限信息 查数据库SimpleAuthorizationInfo simpleAuthorizationInfo new SimpleAuthorizationInfo();//将数据库中查询角色信息赋值给权限对象simpleAuthorizationInfo.addRole(admin);simpleAuthorizationInfo.addRole(super);//将数据库中查询权限信息赋值给权限对象simpleAuthorizationInfo.addStringPermission(user:update:01);simpleAuthorizationInfo.addStringPermission(product:*:*);return simpleAuthorizationInfo;}//认证方法Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {String principal (String) token.getPrincipal();if(xiaochen.equals(principal)){String password 3c88b338102c1a343bcb88cd3878758e;String salt Q4F%;return new SimpleAuthenticationInfo(principal,password, ByteSource.Util.bytes(salt),this.getName());}return null;}} 2.授权 public class TestAuthenticatorCusttomerRealm {public static void main(String[] args) {//创建securityManagerDefaultSecurityManager defaultSecurityManager new DefaultSecurityManager();//IniRealm realm new IniRealm(classpath:shiro.ini);//设置为自定义realm获取认证数据CustomerRealm customerRealm new CustomerRealm();//设置md5加密HashedCredentialsMatcher credentialsMatcher new HashedCredentialsMatcher();credentialsMatcher.setHashAlgorithmName(MD5);credentialsMatcher.setHashIterations(1024);//设置散列次数customerRealm.setCredentialsMatcher(credentialsMatcher);defaultSecurityManager.setRealm(customerRealm);//将安装工具类中设置默认安全管理器SecurityUtils.setSecurityManager(defaultSecurityManager);//获取主体对象Subject subject SecurityUtils.getSubject();//创建token令牌UsernamePasswordToken token new UsernamePasswordToken(xiaochen, 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()){//基于角色权限管理 boolean admin subject.hasRole(admin);System.out.println(admin);//基于多角色权限控制System.out.println(subject.hasRoles(Arrays.asList(admin,super)));//基于权限字符串的访问控制 资源标识符操作资源类型boolean permitted subject.isPermitted(product:create:001);System.out.println(permitted);//分别具有哪些权限boolean[] permittedsubject.isPermitted(user:*:01,order:*:10);for(boolean b:permitted){System.out.println(b);}//同时具有哪些权限boolean permittedAll subject.isPermittedAll(user:*:01, product:*);System.out.println(permittedAll);}} } 6.整合SpringBoot项目实战 6.0 整合思路 6.1 创建springboot项目 创建webapp目录 导入jsp依赖 dependencygroupIdorg.apache.tomcat.embed/groupIdartifactIdtomcat-embed-jasper/artifactId/dependencydependencygroupIdjstl/groupIdartifactIdjstl/artifactIdversion1.2/version/dependency 配置文件配置 spring.application.nameshiro #给应用起个名字 server.port8080 server.servlet.context-path/shirospring.mvc.view.prefix/ spring.mvc.view.suffix.jsp 启动访问出错 原因使用jsp需要配置工作目录 成功 创建jsp页面技巧 直接再页面输入然后按Tab键 访问会出现乱码 加入ok 6.2 引入shiro依赖 dependencygroupIdorg.apache.shiro/groupIdartifactIdshiro-spring-boot-starter/artifactIdversion1.5.3/version /dependency 用jsp实现 //创建配置类 Configuration public class ShiroConfig {//1.创建shiroFilter 负责拦截所有请求Beanpublic ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){ShiroFilterFactoryBean shiroFilterFactoryBean new ShiroFilterFactoryBean();//给filter设置安全管理器shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);//配置系统的受限资源//配置系统公告资源MapString, String map new HashMapString, String();map.put(/index.jsp,authc);//authc 请求index.jsp这个资源需要认证和授权shiroFilterFactoryBean.setFilterChainDefinitionMap(map);//默认认证界面路径 访问受限资源会来到默认认证界面访问index.jsp会重定向到login.jspshiroFilterFactoryBean.setLoginUrl(/login.jsp);return shiroFilterFactoryBean;}//2.创建安全管理器Beanpublic DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm){DefaultWebSecurityManager defaultWebSecurityManager new DefaultWebSecurityManager();//给安全管理器设置defaultWebSecurityManager.setRealm(realm);return defaultWebSecurityManager;}//3.创建自定义realmBeanpublic Realm getRealm(){CustomerRealm customerRealmnew CustomerRealm();return customerRealm;} } public class CustomerRealm extends AuthorizingRealm {Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {return null;}Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {return null;} } 6.3 配置shiro环境 0.创建配置类 1.配置shiroFilterFactoryBean Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager){//创建shiro的filterShiroFilterFactoryBean shiroFilterFactoryBean new ShiroFilterFactoryBean();//注入安全管理器shiroFilterFactoryBean.setSecurityManager(securityManager);return shiroFilterFactoryBean; } 2.配置WebSecurityManager Bean public DefaultWebSecurityManager getSecurityManager(Realm realm){DefaultWebSecurityManager defaultWebSecurityManager new DefaultWebSecurityManager();defaultWebSecurityManager.setRealm(realm);return defaultWebSecurityManager; } 3.创建自定义realm public class CustomerRealm extends AuthorizingRealm {//处理授权Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {return null;}//处理认证Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {return null;} } 4.配置自定义realm //创建自定义realm Bean public Realm getRealm(){return new CustomerRealm(); } 5.编写控制器跳转至index.html Controller //thymeleaf默认不能访问写个控制器 public class IndexController {RequestMapping(index)public String index(){System.out.println(跳转至主页);return index;} } 6.启动springboot应用访问index 注意: 默认在配置好shiro环境后默认环境中没有对项目中任何资源进行权限控制,所有现在项目中所有资源都可以通过路径访问 7.加入权限控制 修改ShiroFilterFactoryBean配置 //注入安全管理器 shiroFilterFactoryBean.setSecurityManager(securityManager); MapString,String map new LinkedHashMap(); map.put(/**,authc); //配置认证和授权规则 shiroFilterFactoryBean.setFilterChainDefinitionMap(map); /** 代表拦截项目中一切资源 authc 代表shiro中的一个filter的别名,详细内容看文档的shirofilter列表 8.重启项目访问查看 (重定向到了login.jsp因为项目是html没有login.jsp所有404) 6.4 常见过滤器 注意: shiro提供和多个默认的过滤器我们可以用这些过滤器来配置控制指定url的权限 配置缩写对应的过滤器功能anonAnonymousFilter指定url可以匿名访问authcFormAuthenticationFilter指定url需要form表单登录默认会从请求中获取username、password,rememberMe等参数并尝试登录如果登录不了就会跳转到loginUrl配置的路径。我们也可以用这个过滤器做默认的登录逻辑但是一般都是我们自己在控制器写登录逻辑的自己写的话出错返回的信息都可以定制嘛。authcBasicBasicHttpAuthenticationFilter指定url需要basic登录logoutLogoutFilter登出过滤器配置指定url就可以实现退出功能非常方便noSessionCreationNoSessionCreationFilter禁止创建会话permsPermissionsAuthorizationFilter需要指定权限才能访问portPortFilter需要指定端口才能访问restHttpMethodPermissionFilter将http请求方法转化成相应的动词来构造一个权限字符串这个感觉意义不大有兴趣自己看源码的注释rolesRolesAuthorizationFilter需要指定角色才能访问sslSslFilter需要https请求才能访问userUserFilter需要已登录或“记住我”的用户才能访问 6.5 认证实现 1. 在login.jsp中开发认证界面 form action${pageContext.request.contextPath}/user/login methodpost用户名:input typetext nameusername br/密码 : input typetext namepassword brinput typesubmit value登录 /form 2. 开发controller Controller RequestMapping(user) public class UserController {/*** 用来处理身份认证* 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.printStackTrace();System.out.println(用户名错误!);}catch (IncorrectCredentialsException e){e.printStackTrace();System.out.println(密码错误!);}return redirect:/login.jsp;} } 在认证过程中使用subject.login进行认证 3.开发realm中返回静态数据(未连接数据库) Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {System.out.println();String principal (String) token.getPrincipal();if(xiaochen.equals(principal)){return new SimpleAuthenticationInfo(principal,123,this.getName());}return null;} } 4.启动项目以realm中定义静态数据进行认证 认证功能没有md5和随机盐的认证就实现啦 6.6 退出认证 1.开发页面退出连接 2.开发controller Controller RequestMapping(user) public class UserController {/*** 退出登录**/RequestMapping(logout)public String logout(){Subject subject SecurityUtils.getSubject();subject.logout();//退出用户return redirect:/login.jsp;} } 3.修改退出连接访问退出路径 4.退出之后访问受限资源立即返回认证界面 MapString, String map new HashMapString, String();map.put(/index.jsp,authc);//authc 请求这个index.jsp资源需要认证和授权shiroFilterFactoryBean.setFilterChainDefinitionMap(map); /index.jsp这种形式要写很多比较麻烦。通常map.put(/**,“authc”); /**表示除了下边配置的login.jsp外所有的都拦截。 MapString, String map new HashMapString, String();map.put(/**,authc); //authc 请求所以的资源需要认证和授权 包括静态map.put(/user/login,anon);//设置为公共资源不放行会进入死循环 放行资源放在下面 shiroFilterFactoryBean.setFilterChainDefinitionMap(map); map.put(/user/login,anon);map.put(/register.jsp,anon);map.put(/user/register,anon);map.put(/**,authc); //authc 请求这个资源需要认证和授权 6.7 MD5、Salt的认证实现 1.开发数据库注册 0.开发注册界面 h1用户注册/h1 form action${pageContext.request.contextPath}/user/register methodpost用户名:input typetext nameusername br/密码 : input typetext namepassword brinput typesubmit value立即注册 /form 1.创建数据表结构 SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0; -- ---------------------------- -- Table structure for t_user -- ---------------------------- DROP TABLE IF EXISTS t_user; CREATE TABLE t_user (id int(6) NOT NULL AUTO_INCREMENT,username varchar(40) DEFAULT NULL,password varchar(40) DEFAULT NULL,salt varchar(255) DEFAULT NULL,PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT2 DEFAULT CHARSETutf8;SET FOREIGN_KEY_CHECKS 1; 2.项目引入依赖 !--mybatis相关依赖-- dependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactIdversion2.1.2/version /dependency!--mysql-- dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion5.1.38/version /dependency!--druid-- dependencygroupIdcom.alibaba/groupIdartifactIddruid/artifactIdversion1.1.19/version /dependency 3.配置application.properties配置文件 server.port8888 server.servlet.context-path/shiro spring.application.nameshirospring.mvc.view.prefix/ spring.mvc.view.suffix.jsp #新增配置 spring.datasource.typecom.alibaba.druid.pool.DruidDataSource spring.datasource.driver-class-namecom.mysql.jdbc.Driver spring.datasource.urljdbc:mysql://localhost:3306/shiro?characterEncodingUTF-8 spring.datasource.usernameroot spring.datasource.passwordrootmybatis.type-aliases-packagecom.baizhi.springboot_jsp_shiro.entity mybatis.mapper-locationsclasspath:com/baizhi/mapper/*.xmllogging.level.com.baizhi.daodebug 打印dao包下的日志 4.创建entity Data Accessors(chain true) AllArgsConstructor NoArgsConstructor public class User {private String id;private String username;private String password;private String salt; } Accessors(chaintrue) 链式访问该注解设置chaintrue生成setter方法返回this也就是返回的是对象代替了默认的返回void。 public static void main(String[] args) {//开起chaintrue后可以使用链式的setUser usernew User().setAge(31).setName(pollyduan);//返回对象System.out.println(user);} 5.创建DAO接口 Mapper public interface UserDAO {void save(User user); } 6.开发mapper配置文件 insert idsave parameterTypeUser useGeneratedKeystrue keyPropertyidinsert into t_user values(#{id},#{username},#{password},#{salt}) /insert 7.开发service接口 public interface UserService {//注册用户方法void register(User user); } 8.创建salt工具类 public class SaltUtils {/*** 生成salt的静态方法* param n* return*/public static String getSalt(int n){char[] chars ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890!#$%^*().toCharArray();StringBuilder sb new StringBuilder();for (int i 0; i n; i) {char aChar chars[new Random().nextInt(chars.length)];sb.append(aChar);}return sb.toString();} } 9.开发service实现类 Service Transactional public class UserServiceImpl implements UserService {Autowiredprivate UserDAO userDAO;Overridepublic void register(User user) {//处理业务调用dao//1.生成随机盐String salt SaltUtils.getSalt(8);//2.将随机盐保存到数据user.setSalt(salt);//3.明文密码进行md5 salt hash散列Md5Hash md5Hash new Md5Hash(user.getPassword(),salt,1024);user.setPassword(md5Hash.toHex());userDAO.save(user);} } 10.开发Controller 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;}} } 11.启动项目进行注册 2.开发数据库认证 0.开发DAO Mapper public interface UserDAO {void save(User user);//根据身份信息认证的方法User findByUserName(String username); } 1.开发mapper配置文件 select idfindByUserName parameterTypeString resultTypeUserselect id,username,password,salt from t_userwhere username #{username} /select 2.开发Service接口 public interface UserService {//注册用户方法void register(User user);//根据用户名查询业务的方法User findByUserName(String username); } 3.开发Service实现类 Service(userService) Transactional public class UserServiceImpl implements UserService {Autowiredprivate UserDAO userDAO;Overridepublic User findByUserName(String username) {return userDAO.findByUserName(username);} } 4.开发在工厂中获取bean对象的工具类当有别的bean要被注入时由于局限原因不能使用Component直接注入时可以使用该方法在这里因为 自定义realm的认证阶段属于filter当时的spring bean还没有读取进来 Component public class ApplicationContextUtils implements ApplicationContextAware {private static ApplicationContext context;Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.context applicationContext;}//根据bean名字获取工厂中指定bean 对象public static Object getBean(String beanName){return context.getBean(beanName);} } 5.修改自定义realm Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {System.out.println();//根据身份信息String principal (String) token.getPrincipal();//在工厂中获取service对象UserService userService (UserService) ApplicationContextUtils.getBean(userService);//根据身份信息查询User user userService.findByUserName(principal);//!ObjectUtils.isEmpty(user)和user!null一样if(!ObjectUtils.isEmpty(user)){ //返回数据库信息return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(), ByteSource.Util.bytes(user.getSalt()),this.getName());}return null;} 6.修改ShiroConfig中realm使用凭证匹配器以及hash散列 Bean public Realm getRealm(){CustomerRealm customerRealm new CustomerRealm();//设置hashed凭证匹配器HashedCredentialsMatcher credentialsMatcher new HashedCredentialsMatcher();//设置md5加密credentialsMatcher.setHashAlgorithmName(md5);//设置散列次数credentialsMatcher.setHashIterations(1024);customerRealm.setCredentialsMatcher(credentialsMatcher);return customerRealm; } 6.8 授权实现 0.页面资源授权jsp页面 //引入标签 %taglib prefixshiro urihttp://shiro.apache.org/tags %shiro:hasAnyRoles nameuser,adminlia href用户管理/aulshiro:hasPermission nameuser:add:* 资源权限lia href添加/a/li/shiro:hasPermissionshiro:hasPermission nameuser:delete:*lia href删除/a/li/shiro:hasPermissionshiro:hasPermission nameuser:update:*lia href修改/a/li/shiro:hasPermissionshiro:hasPermission nameuser:find:*lia href查询/a/li/shiro:hasPermission/ul/li/shiro:hasAnyRoles 角色权限shiro:hasRole nameadminlia href商品管理/a/lilia href订单管理/a/lilia href物流管理/a/li/shiro:hasRole 1.代码方式授权 RequestMapping(save) public String save(){System.out.println(进入方法);//获取主体对象Subject subject SecurityUtils.getSubject();//代码方式if (subject.hasRole(admin)) {System.out.println(保存订单!);}else{System.out.println(无权访问!);}//基于权限字符串//....return redirect:/index.jsp; } 2.方法调用授权 RequiresRoles 用来基于角色进行授权RequiresPermissions 用来基于权限进行授权 RequestMapping(order) public class OrderController(){RequiresRoles(value{admin,user})//用来判断角色 同时具有 admin usercRequiresPermissions(user:update:01) //用来判断权限字符串RequestMapping(save)public String save(){System.out.println(进入方法);return redirect:/index.jsp;} } 3.授权数据持久化 SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0;-- ---------------------------- -- Table structure for t_pers -- ---------------------------- DROP TABLE IF EXISTS t_pers; CREATE TABLE t_pers (id int(6) NOT NULL AUTO_INCREMENT,name varchar(80) DEFAULT NULL,url varchar(255) DEFAULT NULL,PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8;-- ---------------------------- -- Table structure for t_role -- ---------------------------- DROP TABLE IF EXISTS t_role; CREATE TABLE t_role (id int(6) NOT NULL AUTO_INCREMENT,name varchar(60) DEFAULT NULL,PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8;-- ---------------------------- -- Table structure for t_role_perms -- ---------------------------- DROP TABLE IF EXISTS t_role_perms; CREATE TABLE t_role_perms (id int(6) NOT NULL,roleid int(6) DEFAULT NULL,permsid int(6) DEFAULT NULL,PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8;-- ---------------------------- -- Table structure for t_user -- ---------------------------- DROP TABLE IF EXISTS t_user; CREATE TABLE t_user (id int(6) NOT NULL AUTO_INCREMENT,username varchar(40) DEFAULT NULL,password varchar(40) DEFAULT NULL,salt varchar(255) DEFAULT NULL,PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT2 DEFAULT CHARSETutf8;-- ---------------------------- -- Table structure for t_user_role -- ---------------------------- DROP TABLE IF EXISTS t_user_role; CREATE TABLE t_user_role (id int(6) NOT NULL,userid int(6) DEFAULT NULL,roleid int(6) DEFAULT NULL,PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8;SET FOREIGN_KEY_CHECKS 1; entity实体类 Data AllArgsConstructor NoArgsConstructor Accessors(chain true) public class User {private String id;private String username;private String password;private String salt;private ListRole roles;//定义角色集合 }AllArgsConstructor NoArgsConstructor Accessors(chain true) public class Role {private String id;private String name; }public class Perms {private String id;private String name;private String url; } 4.创建dao方法 //根据用户名查询所有角色 User findRolesByUserName(String username); //根据角色id查询权限集合 ListPerms findPermsByRoleId(String id); 5.mapper实现 resultMap iduserMap typeUserid columnuid propertyid/result columnusername propertyusername/!--角色信息-- //里边装的是什么类型collection propertyroles javaTypelist ofTypeRole // ***********id columnid propertyid/result columnrname propertyname//collection /resultMapselect idfindRolesByUserName parameterTypeString resultMapuserMapSELECT u.id uid,u.username,r.id,r.NAME rnameFROM t_user uLEFT JOIN t_user_role urON u.idur.useridLEFT JOIN t_role rON ur.roleidr.idWHERE u.username#{username} /selectselect idfindPermsByRoleId parameterTypeString resultTypePermsSELECT p.id,p.NAME,p.url,r.NAMEFROM t_role rLEFT JOIN t_role_perms rpON r.idrp.roleidLEFT JOIN t_perms p ON rp.permsidp.idWHERE r.id#{id} /select 6.Service接口 //根据用户名查询所有角色 User findRolesByUserName(String username); //根据角色id查询权限集合 ListPerms findPermsByRoleId(String id); 7.Service实现 Override public ListPerms findPermsByRoleId(String id) {return userDAO.findPermsByRoleId(id); }Override public User findRolesByUserName(String username) {return userDAO.findRolesByUserName(username); } 8.修改自定义realm CollectionUtils.isEmpty(user.getRoles())角色是否为空 public class CustomerRealm extends AuthorizingRealm {Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {//获取身份信息String primaryPrincipal (String) principals.getPrimaryPrincipal();//根据主身份信息获取角色 和 权限信息UserService userService (UserService) ApplicationContextUtils.getBean(userService);User user userService.findRolesByUserName(primaryPrincipal);//授权角色信息 !CollectionUtils.isEmpty(user.getRoles())if(!CollectionUtils.isEmpty(user.getRoles())){SimpleAuthorizationInfo simpleAuthorizationInfo new SimpleAuthorizationInfo();user.getRoles().forEach(role-{simpleAuthorizationInfo.addRole(role.getName());//到此授权角色信息结束可以只做角色信息看要求//权限信息ListPerms perms userService.findPermsByRoleId(role.getId());if(!CollectionUtils.isEmpty(perms)){perms.forEach(perm-{simpleAuthorizationInfo.addStringPermission(perm.getName());});}});return simpleAuthorizationInfo;}return null;} } 9.启动测试 6.9 使用CacheManager 页面中有权限的数据每次访问每次刷新都会重新访问一次数据库一个用户的权限数据基本不会经常发生变化。每一次刷新都会去调用doGetAuthorizationInfo去数据库获取信息。 1.Cache 作用 Cache 缓存: 计算机内存中一段数据作用: 用来减轻DB的访问压力,从而提高系统的查询效率流程: 在内存中存放每次获取会很快。查询多增删少 2.使用shiro中默认EhCache实现缓存 EhCache 是一个纯Java的进程内缓存框架具有快速、精干等特点是Hibernate中默认的CacheProvider缓存产品。 公司中大多数用redis做缓存。 1.引入依赖 !--引入shiro和ehcache-- dependencygroupIdorg.apache.shiro/groupIdartifactIdshiro-ehcache/artifactIdversion1.5.3/version /dependency 2.开启缓存 //3.创建自定义realmBeanpublic Realm getRealm(){CustomerRealm customerRealm new CustomerRealm();//修改凭证校验匹配器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(authenorizationCache);return customerRealm;} 只有第一次会去数据库查找之后在缓存中找。 在自己应用的一块内存里边关掉程序就没有了还会去查数据库实现的是本地缓存就是应用内部的缓存。可以结合redis做成分布式缓存把缓存放在redis中与当前应用是否宕机、停止没有关系只要redis中有缓存每次都去缓存中找不去数据库。 3.启动刷新页面进行测试 注意:如果控制台没有任何sql展示说明缓存已经开启 3.shiro中使用Redis作为缓存实现 1.引入redis依赖 !--redis整合springboot-- dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId /dependency 2.配置redis连接 spring.redis.port6379 spring.redis.hostlocalhost spring.redis.database0 3.启动redis服务 ➜ bin ls dump.rdb redis-check-aof redis-cli redis-server redis.conf redis-benchmark redis-check-rdb redis-sentinel redis-trib.rb ➜ bin ./redis-server redis.conf 4.开发RedisCacheManager //自定义shiro缓存管理器 public class RedisCacheManager implements CacheManager {Override //参数认证或者是授权缓存的统一名称public K, V CacheK, V getCache(String cacheName) throws CacheException {System.out.println(缓存名称: cacheName);return new RedisCacheK,V(cacheName); //也可以不传参数} } 5.开发RedisCache实现 public class RedisCacheK,V implements CacheK,V { Overridepublic V get(K k) throws CacheException {System.out.println(获取缓存: k); return (V) getRedisTemplate().opsForValue().get(k.toString());}Overridepublic V put(K k, V v) throws CacheException {System.out.println(设置缓存key: k value:v);getRedisTemplate().opsForValue().set(k.toString(),v);return null;}...... } //以上这些是使用无参构造没有管cacheNameRedisCacheManager类中方 //法返回return new RedisCacheK,V();无参 如果想要把缓存名字也考虑进去用下面这种。用Hash模型getRedisTemplate().opsForHash()… map里边还有map相当于MapString,MapString,Object大key需要序列化内部key也要序列化。 public class RedisCacheK,V implements CacheK,V {private String cacheName//有参构造有、public RedisCache() {}public RedisCache(String cacheName) {this.cacheName cacheName;}Overridepublic V get(K k) throws CacheException {System.out.println(获取缓存: k); return (V) getRedisTemplate().opsForHash().get(this.cacheName,k.toString());}Overridepublic V put(K k, V v) throws CacheException {System.out.println(设置缓存key: k value:v);getRedisTemplate().opsForHash().put(this.cacheName,k.toString(),v);return null;}//点击退出用户调用的是remove()不是clear() 只有一个用户访问时点击退出下一次会去数据库查找缓存中没有了因为只有一条用户的数据map中没有数据时就会把整个map清空掉。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();//前边返回long类型intValue()使其返回int类型}Overridepublic Setk keys() {return getRedisTemplate().opsForHash().keys(this.cacheName);}Overridepublic Collectionv values() {return getRedisTemplate().opsForHash().values(this.cacheName);}//封装获取redisTemplate//简化书写 上边都需要redisTemplate 做一个简单的封装private RedisTemplate getRedisTemplate(){RedisTemplate redisTemplate (RedisTemplate) ApplicationContextUtils.getBean(redisTemplate);redisTemplate.setKeySerializer(new StringRedisSerializer());大key序列化redisTemplate.setHashKeySerializer(new StringRedisSerializer());//内部key序列化return redisTemplate;} } new RedisCacheManager() Configuration public class ShiroConfig {Beanpublic Realm getRealm(){CustomerRealm realm new CustomerRealm();HashedCredentialsMatcher credentialsMatcher new HashedCredentialsMatcher();credentialsMatcher.setHashAlgorithmName(md5);credentialsMatcher.setHashIterations(1024);realm.setCredentialsMatcher(credentialsMatcher);realm.setCacheManager(new RedisCacheManager()); //*************realm.setCachingEnabled(true);realm.setAuthenticationCachingEnabled(true);realm.setAuthorizationCachingEnabled(true);return realm;} } redis默认使用对象序列化策略所有存入对象后get看到的是一串字符。 6.启动项目测试发现报错 错误解释: 由于shiro中提供的simpleByteSource实现没有实现序列化,所以在认证时出现错误信息 解决方案: 需要自动salt实现序列化 自定义salt实现序列化 //自定义salt实现 实现序列化接口 public class MyByteSource extends SimpleByteSource implements Serializable {public MyByteSource(String string) {super(string);} } 在realm中使用自定义salt new MyByteSource(user.getSalt()) Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {System.out.println();//根据身份信息String principal (String) token.getPrincipal();//在工厂中获取service对象UserService userService (UserService) ApplicationContextUtils.getBean(userService);User user userService.findByUserName(principal);if(!ObjectUtils.isEmpty(user)){return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(), new MyByteSource(user.getSalt()),this.getName());}return null; } [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SUEMGZ8F-1631715710787)(Shiro 实战教程.assets/image-20200530101301543.png)] 7.再次启动测试,发现可以成功放入redis缓存下面就是序列化后的对象 第一行记录授权信息 第二行记录认证信息 要使用hash命令进行操作 hgetall hgetall com.baizhi.shiro.realm.CustomerRealm.authenticationCache 4. 加入验证码验证 把之前的验证码工具类VeriffyCodeUtils拿来用放到utils中。 0.开发页面加入验证码 开发控制器 RequestMapping(getImage) public void getImage(HttpSession session, HttpServletResponse response) throws IOException {//生成验证码String code VerifyCodeUtils.generateVerifyCode(4);//验证码放入sessionsession.setAttribute(code,code);//之后要取出验证//验证码存入图片ServletOutputStream os response.getOutputStream();response.setContentType(image/png);//响应流类型VerifyCodeUtils.outputImage(220,60,os,code); } 放行验证码 开发页面 form action${pageContext.request.contextPath}/user/login methodpost用户名input typetext nameusernamebr密nbsp;码input typetext namepasswordbr请输入验证码input typetext namecodeimg src${pageContext.request.contextPath}/user/getImage altbrinput typesubmit value登录 /form 修改认证流程 RequestMapping(login)public String login(String username, String password,String code,HttpSession session) {//比较验证码String codes (String) session.getAttribute(code);try {if (codes.equalsIgnoreCase(code)){//获取主体对象Subject subject SecurityUtils.getSubject();subject.login(newUsernamePasswordToken(username,password));return redirect:/index.jsp;}else{throw new RuntimeException(验证码错误!);}} catch (UnknownAccountException e) {e.printStackTrace();System.out.println(用户名错误!);} catch (IncorrectCredentialsException e) {e.printStackTrace();System.out.println(密码错误!);}catch (Exception e){e.printStackTrace();System.out.println(e.getMessage());}return redirect:/login.jsp;} 访问出现错误 ​ no valid constructor 没有有效的构造函数 原因MyByteSource没有无参构造Redis在反序列化时要用到无参构造。 用下面的办法解决implements ByteSource,Serializable然后把SimpleByteSource中全部内容拿出来改造把里边SimpleByteSource换成MyByteSource在加入一个无参构造这个无参构造仅仅用来做序列化。 修改salt不能序列化的问题 //之前继承MyByteSource extends SimpleByteSource。SimpleByteSource中没有无参构造无参构造Redis反序列化时要使用所以自己需要在实现一个。 //*父类没有无参构造子类也不能有无参构造因为子类第一行默认调用父类无参构造super() //自定义salt实现 实现序列化接口 把SimpleByteSource中全部内容拿出来改造 public class MyByteSource implements ByteSource,Serializable {//加入无参数构造方法实现序列化和反序列化public MyByteSource(){}private byte[] bytes;private String cachedHex;private String cachedBase64;public MyByteSource(byte[] bytes) {this.bytes bytes;}public MyByteSource(char[] chars) {this.bytes CodecSupport.toBytes(chars);}public MyByteSource(String string) {this.bytes CodecSupport.toBytes(string);}public MyByteSource(ByteSource source) {this.bytes source.getBytes();}public MyByteSource(File file) {this.bytes (new MyByteSource.BytesHelper()).getBytes(file);}public MyByteSource(InputStream stream) {this.bytes (new MyByteSource.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);}} } 页面展示用户身份信息jsp中 shiro:principal/ 拿到用户主身份信息 shiro:authenticated认证之后展示的内容 /shiro:authenticatedshiro:noAuthenticated没有认证展示的内容 /shiro:noAuthenticated 7.Shiro整合springboot之thymeleaf权限控制 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-thymeleaf/artifactId /dependency spring.thymeleaf.cachefalse spring.thymeleaf.prefixclasspath:/templates/ spring.thymeleaf.suffix.html spring.resources.static-locationsclasspath:/static/ #调整静态资源位置默认也是这里可以不写当想要改变位置时配置 !doctype html html langen xmlns:thhttp://www.thymeleaf.org head /head body h1用户登录/h1 form th:action{/user/login} methodpost用户名input typetext nameusernamebr密nbsp;码input typetext namepasswordbr请输入验证码input typetext namecodeimg th:src{/user/getImage}brinput typesubmit value登录 /form /body /html 上边这些是常规的thymeleaf操作。 1.引入扩展依赖 dependencygroupIdcom.github.theborakompanioni/groupIdartifactIdthymeleaf-extras-shiro/artifactIdversion2.0.0/version /dependency 2.页面中引入命名空间 xmlns:shiro“http://www.pollix.at/thymeleaf/shiro” html xmlnshttp://www.w3.org/1999/xhtml xmlns:thhttp://www.thymeleaf.orgxmlns:shirohttp://www.pollix.at/thymeleaf/shiro ...... 3.常见权限控制标签使用 !-- 验证当前用户是否为“访客”即未认证包含未记住的用户。 -- p shiro:guestPlease a hreflogin.htmllogin/a/p!-- 认证通过或已记住的用户。 -- p shiro:userWelcome back John! Not John? Click a hreflogin.htmlhere/a to login. /p!-- 已认证通过的用户。不包含已记住的用户这是与user标签的区别所在。 -- p shiro:authenticatedHello, span shiro:principal/span, how are you today? /p a shiro:authenticated hrefupdateAccount.htmlUpdate your contact information/a!-- 输出当前用户信息通常为登录帐号信息。 -- pHello, shiro:principal/, how are you today?/p!-- 未认证通过用户与authenticated标签相对应。与guest标签的区别是该标签包含已记住用户。 -- p shiro:notAuthenticatedPlease a hreflogin.htmllogin/a in order to update your credit card information. /p!-- 验证当前用户是否属于该角色。 -- a shiro:hasRoleadmin hrefadmin.htmlAdminister the system/a!-- 拥有该角色 --!-- 与hasRole标签逻辑相反当用户不属于该角色时验证通过。 -- p shiro:lacksRoledeveloper!-- 没有该角色 --Sorry, you are not allowed to developer the system. /p!-- 验证当前用户是否属于以下所有角色。 -- p shiro:hasAllRolesdeveloper, 2!-- 角色与判断 --You are a developer and a admin. /p!-- 验证当前用户是否属于以下任意一个角色。 -- p shiro:hasAnyRolesadmin, vip, developer,1!-- 角色或判断 --You are a admin, vip, or developer. /p!--验证当前用户是否拥有指定权限。 -- a shiro:hasPermissionuserInfo:add hrefcreateUser.html添加用户/a!-- 拥有权限 --!-- 与hasPermission标签逻辑相反当前用户没有制定权限时验证通过。 -- p shiro:lacksPermissionuserInfo:del!-- 没有权限 --Sorry, you are not allowed to delete user accounts. /p!-- 验证当前用户是否拥有以下所有角色。 -- p shiro:hasAllPermissionsuserInfo:view, userInfo:add!-- 权限与判断 --You can see or add users. /p!-- 验证当前用户是否拥有以下任意一个权限。 -- p shiro:hasAnyPermissionsuserInfo:view, userInfo:del!-- 权限或判断 --You can see or delete users. /p a shiro:hasPermissionpp hrefcreateUser.htmlCreate a new User/a 4.加入shiro的方言配置 页面标签不起作用一定要记住加入方言处理 //在ShiroConfig配置文件中 Bean(name shiroDialect) public ShiroDialect shiroDialect(){return new ShiroDialect(); }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/88782.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

温岭企业网站建设公司昆明网站建设公司排名猫咪科技

如今科技发达的时代,手机的功能不仅仅只是能通讯聊天,而是逐渐的走进了人们的生活中。因为有了APP,我们的生活才更丰富,并且有很多是我们生活中不可缺少的软件,而这些软件便是根据手机中的GPS定位系统而来的。简单来说…

百度收录网站多久利用wordpress打包成百度小程序

题目描述 今天小明去了一个风景如画的地方散心,但是自己带的饮料喝完了,小明口渴难耐,见不远处有家小商店,于是跑去买饮料。小明:“我要买饮料!”店主:“我们这里有三种饮料,矿泉水1…

厦门app网站设计成都seo专家

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战,欢迎高校老师\讲师\同行交流合作 ​主要内容:毕业设计(Javaweb项目|小程序|Pyt…

做域名代理网站百度的广告怎么免费发布

从年初时的踌躇满志,到年中时整个业务线被砍。全职做前端训练营,四个多月的时间帮助100多名同学拿到了满意的offer,同时也让我的收入重归正轨。仅以这个视频记录我,一个普通程序员的 2023 。 视频版可直接访问 Hello,大…

网页网站开发工具wordpress腾讯地图插件下载

Markdown会干掉Html吗? 很明显,MarkDown正在已一种比病毒还快的速度传播着,量子的机器人语言也是深受其启发,当然了,在这个东西没搞出来之前,MarkDown就能干很多事情,比如在线编辑。 有了它&…

网站该怎么做wordpress 中文在线字体

可选题目三:TCP/IP协议栈在Linux内核中的运行时序分析在深入理解Linux内核任务调度(中断处理、softirg、tasklet、wq、内核线程等)机制的基础上,分析梳理send和recv过程中TCP/IP协议栈相关的运行任务实体及相互协作的时序分析。编译、部署、运行、测评、…

建立网站流程图wordpress iis6 伪静态

pycharm简介PyCharm是一种Python IDE,带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具,比如调试、语法高亮、Project管理、代码跳转、智能提示、自动完成、单元测试、版本控制。此外,该IDE提供了一些高级功能,以用…

godaddy如何创建网站做牙齿的招聘网站

利用二极管(开关器件)的单向导电特性,和放大器的优良放大性能相结合,可做到对输入交变信号(尤其是小幅度的电压信号)进行精密的整流,由此构成精密半波整流电路。若由此再添加简单电路,即可构成精密全波整流电路。二极管的导通压降…

网站外链接自己可以怎么做的内销网站要怎么做

部署静态文件: 静态文件有两种方式 1:通过django路由访问 2:通过nginx直接访问 方式1: 需要在根目录的URL文件中增加 url(r^$, TemplateView.as_view(template_name"index.html")),作为入口,在setting中更改…

2008 iis 网站自己开发app要钱吗

私有继承 在C中,私有继承是一种继承方式,它定义了一个私有派生类,也称为派生类。私有继承意味着派生类继承了基类的所有成员,但这些成员在派生类中是私有的,对外部不可见。 要进行私有继承请使用private关键字&#…

有系统源码可以做网站吗设备网站建设

2019.2.14 情人节,Filecoin项目开放了核心源码仓库go-filecoin,并更新了 filecoin-project organization下的诸多核心成果,这意味着,Filecoin已然度过了最困难的难点攻关期,进入到了全民公测阶段。 本系列文章将协助大…

a站为什么会凉制作网站的软件有那个免费

文章目录 UDP协议?什么是校验和?基于UDP的应用层协议(了解) TCP协议确认应答(可靠性机制)超时重传(可靠性机制)连接管理(可靠性机制)三次握手(重点)四次挥手(重点) 三次握手和四次挥手时客户端和服务器的状态滑动窗口(效率机制)流量控制(效率机制)窗口探…

企业网站建设的流程与原则公司网站制作公司

做Linux方面也有三个多月了,对代码中的有些结构一直不是非常明确,比方platform_device与platform_driver一直分不清关系。在网上搜了下,做个总结。两者的工作顺序是先定义platform_device -> 注冊 platform_device->,再定义…

重庆网站建设哪家做的好网站建设主流语言

这是Project Student的一部分。 其他职位包括带有Jersey的 Web服务 客户端,带有Jersey的 Web服务服务器 , 业务层和带有Spring Data的持久性 。 到目前为止,所有集成测试都使用了内存嵌入式数据库,该数据库无法一次又一次地保留信…

游戏的网站seo推广软件

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼6、free()函数问:下面的程序会在用户输入’freeze’的时候出问题,而’zebra’则不会,为什么?#include int main(int argc, char *argv[]) {char *ptr (char*)malloc(10);if(NULL ptr){printf(…

媒体网站开发字体设计在线生成

链接:https://pan.baidu.com/s/1-tCCFwZ0RggXtbWYBVyhFg?pwdmcgv 提取码:mcgv 华为MageBookD14原厂WIN11系统自带所有驱动、出厂状态主题壁纸、Office办公软件、华为电脑管家、华为应用市场等预装软件程序 文件格式:esd/wim/swm 安装方式…

购物网站设计需要哪些模块优秀英文企业网站

广搜练手题 题目链接 思路 打印每个数与其最近的 1 1 1的曼哈顿距离&#xff0c;显然广搜&#xff0c;存储每一个 1 1 1&#xff0c;针对每一个 1 1 1开始广搜&#xff0c;逐层更新&#xff0c;每轮后更新的为两轮之中的最小曼哈顿距离 ACcode #include<bits/stdc.h>…

有专门做辩论的网站吗如何推广自己的网址

&#xff08;笔记&#xff0c;只为获取流量券&#xff09; MySQL中&#xff0c;UPDATE 操作涉及到行级锁和表级锁的概念&#xff0c;具体取决于事务隔离级别和被更新的条件, 无索引的情况下&#xff1a; 当表没有索引的情况下&#xff0c;UPDATE 操作通常会涉及到表级锁。这是…

辽宁城建设计院有限公司网站公司网站建设费用会计科目

说明&#xff1a;基于filebeat采集日志 概述&#xff1a; 在Kubernetes环境中&#xff0c;Filebeat不需要和业务服务部署在同一个容器中。通常的做法是将Filebeat作为一个DaemonSet部署在集群中&#xff0c;这样它可以在每个节点上运行一个实例&#xff0c;并从所有容器中收集…

网站开发文档包括广州番禺区核酸检测点

什么是守护进程&#xff1f;答&#xff1a;守护进程是后台运行的、系统启动是就存在的、不予任何终端关联的&#xff0c;用于处理一些系统级别任务的特殊进程。实现思路&#xff1a;实现一个守护进程&#xff0c;其实就是将普通进程按照上述特性改造为守护进程的过程。需要注意…