SpringBoot整合Shiro和Redis的示例代碼
此demo用SpringBoot+Shiro簡單實(shí)現(xiàn)了登陸、注冊、認(rèn)證、授權(quán)的功能,并用redis做分布式緩存提高性能。
1.準(zhǔn)備工作
導(dǎo)入pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.2.RELEASE</version> </parent> <groupId>com.ego</groupId> <artifactId>shirodemo</artifactId> <version>1.0-SNAPSHOT</version> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> <version>4.4.13</version> </dependency> <!-- 引入jsp依賴 --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> </dependency> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- shiro --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.5.3</version> </dependency> <!-- mybatis plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.1</version> </dependency> <!-- Druid數(shù)據(jù)源 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <!-- Mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.5.3</version> </dependency> <!-- 引入redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> </dependencies> </project>
配置yml文件
spring: # 設(shè)置視圖模板為jsp mvc: view: prefix: / suffix: .jsp datasource: type: com.alibaba.druid.pool.DruidDataSource druid: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=UTC username: root password: root # 監(jiān)控統(tǒng)計攔截的filters filters: stat,wall,log4j,config # 配置初始化大小/最小/最大 initial-size: 5 min-idle: 5 max-active: 20 # 獲取連接等待超時時間 max-wait: 60000 # 間隔多久進(jìn)行一次檢測,檢測需要關(guān)閉的空閑連接 time-between-eviction-runs-millis: 60000 # 一個連接在池中最小生存的時間 min-evictable-idle-time-millis: 300000 validation-query: SELECT 'x' test-while-idle: true test-on-borrow: false test-on-return: false # 打開PSCache,并指定每個連接上PSCache的大小。oracle設(shè)為true,mysql設(shè)為false。分庫分表較多推薦設(shè)置為false pool-prepared-statements: false max-pool-prepared-statement-per-connection-size: 20 redis: host: 127.0.0.1 port: 6379 password: abc123456 database: 0 mybatis-plus: type-aliases-package: com.ego.pojo configuration: map-underscore-to-camel-case: true
2.編寫index,login,register三個JSP
<%--解決頁面亂碼--%> <%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %> <!doctype html> <html lang="en"> <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>index</title> </head> <body> <form action="${pageContext.request.contextPath}/user/login" method="post"> 用戶名:<input type="text" name="username" > <br/> 密碼 : <input type="text" name="password"> <br> <input type="submit" value="登錄"> </form> </body> </html> <%--解決頁面亂碼--%> <%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %> <%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %> <!doctype html> <html lang="en"> <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>index</title> </head> <body> <h1>系統(tǒng)主頁</h1> <a href="${pageContext.request.contextPath}/user/logout">退出用戶</a> <ul> <%-- admin角色的用戶能同時擁有用戶管理和訂單管理的權(quán)限,user角色的用戶只擁有訂單管理的權(quán)限 --%> <shiro:hasRole name="admin"> <li> <a href="">用戶管理</a> </li> </shiro:hasRole> <%-- admin角色的用戶對訂單有增刪改查的權(quán)限,user角色的用戶只能查看訂單 --%> <shiro:hasAnyRoles name="admin,user"> <li> <a href="">訂單管理</a> <ul> <shiro:hasPermission name="order:add:*"> <li><a href="">新增</a></li> </shiro:hasPermission> <shiro:hasPermission name="order:del:*"> <li><a href="">刪除</a></li> </shiro:hasPermission> <shiro:hasPermission name="order:upd:*"> <li><a href="">修改</a></li> </shiro:hasPermission> <shiro:hasPermission name="order:find:*"> <li><a href="">查詢</a></li> </shiro:hasPermission> </ul> </li> </shiro:hasAnyRoles> </ul> </body> </html> <%--解決頁面亂碼--%> <%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %> <!doctype html> <html lang="en"> <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>register</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>
3.實(shí)現(xiàn)User、Role、Permission三個POJO
package com.ego.pojo; import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * @author 袁夢達(dá) 2019012364 */ @Data @NoArgsConstructor @AllArgsConstructor @TableName("t_user") @ApiModel("用戶實(shí)體類") public class User implements Serializable { /** 數(shù)據(jù)庫中設(shè)置該字段自增時該注解不能少 **/ @TableId(type = IdType.AUTO) @ApiModelProperty(name = "id", value = "ID 主鍵") private Integer id; @TableField(fill = FieldFill.INSERT_UPDATE) @ApiModelProperty(name = "username", value = "用戶名") private String username; @TableField(fill = FieldFill.INSERT_UPDATE) @ApiModelProperty(name = "password", value = "密碼") private String password; @TableField(fill = FieldFill.INSERT) @ApiModelProperty(name = "salt", value = "鹽") private String salt; @TableField(fill = FieldFill.INSERT_UPDATE) @ApiModelProperty(name = "age", value = "年齡") private Integer age; @TableField(fill = FieldFill.INSERT_UPDATE) @ApiModelProperty(name = "email", value = "郵箱") private String email; @TableField(fill = FieldFill.INSERT_UPDATE) @ApiModelProperty(name = "address", value = "地址") private String address; @TableField(exist = false) private List<Role> roles = new ArrayList<>(); } package com.ego.pojo; import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * @author 袁夢達(dá) 2019012364 */ @Data @NoArgsConstructor @AllArgsConstructor @TableName("t_role") @ApiModel("角色實(shí)體類") public class Role implements Serializable { /** 數(shù)據(jù)庫中設(shè)置該字段自增時該注解不能少 **/ @TableId(type = IdType.AUTO) @ApiModelProperty(name = "id", value = "ID 主鍵") private Integer id; @TableField(fill = FieldFill.INSERT_UPDATE) @ApiModelProperty(name = "name", value = "角色名稱") private String name; @TableField(exist = false) private List<Permission> permissions = new ArrayList<>(); } package com.ego.pojo; import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; /** * @author 袁夢達(dá) 2019012364 */ @Data @NoArgsConstructor @AllArgsConstructor @TableName("t_permission") @ApiModel("權(quán)限實(shí)體類") public class Permission implements Serializable { /** 數(shù)據(jù)庫中設(shè)置該字段自增時該注解不能少 **/ @TableId(type = IdType.AUTO) @ApiModelProperty(name = "id", value = "ID主鍵") private Integer id; @TableField(fill = FieldFill.INSERT_UPDATE) @ApiModelProperty(name = "name", value = "權(quán)限名稱") private String name; @TableField(fill = FieldFill.INSERT_UPDATE) @ApiModelProperty(name = "url", value = "權(quán)限菜單URL") private String url; }
4.實(shí)現(xiàn)Controller、Service、Dao
這里dao采用了mybatis-plus
package com.ego.controller; import com.ego.pojo.User; import com.ego.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; /** * @author 袁夢達(dá) 2019012364 */ @Controller @RequestMapping("/user") public class UserController { @Autowired private UserService userService; /** * 用戶登錄 * @param username * @param password * @return */ @RequestMapping("/login") public String login(String username,String password){ // 獲取當(dāng)前登錄用戶 Subject subject = SecurityUtils.getSubject(); try { // 執(zhí)行登錄操作 subject.login(new UsernamePasswordToken(username,password)); // 認(rèn)證通過后直接跳轉(zhuǎn)到index.jsp return "redirect:/index.jsp"; } catch (UnknownAccountException e) { e.printStackTrace(); System.out.println("用戶名錯誤!"); } catch (IncorrectCredentialsException e) { System.out.println("密碼錯誤!"); } catch (Exception e) { } // 如果認(rèn)證失敗仍然回到登錄頁面 return "redirect:/login.jsp"; } @RequestMapping("/logout") public String logout(){ subject.logout(); // 退出后仍然會到登錄頁面 * 用戶注冊 * @param user @RequestMapping("/register") public String register(User user){ userService.register(user); return "redirect:/login.jsp"; return "redirect:/register.jsp"; } package com.ego.service.impl; import com.ego.dao.mapper.UserMapper; import com.ego.shiro.ShiroConstant; import com.ego.utils.SaltUtil; import org.apache.shiro.crypto.hash.Md5Hash; import org.springframework.stereotype.Service; @Service("userService") public class UserServiceImpl implements UserService { private UserMapper userMapper; @Override public void register(User user) { //生成隨機(jī)鹽 String salt = SaltUtil.getSalt(ShiroConstant.SALT_LENGTH); //保存隨機(jī)鹽 user.setSalt(salt); //生成密碼 Md5Hash password = new Md5Hash(user.getPassword(), salt, ShiroConstant.HASH_ITERATORS); //保存密碼 user.setPassword(password.toHex()); userMapper.insert(user); public User findUserByUserName(String userName) { return userMapper.findUserByUserName(userName); import com.ego.dao.mapper.RoleMapper; import com.ego.pojo.Role; import com.ego.service.RoleService; import java.util.List; @Service("roleService") public class RoleServiceImpl implements RoleService { private RoleMapper roleMapper; public List<Role> getRolesByUserId(Integer userId) { return roleMapper.getRolesByUserId(userId); import com.ego.dao.mapper.PermissionMapper; import com.ego.pojo.Permission; import com.ego.service.PermissionService; @Service("permissionService") public class PermissionServiceImpl implements PermissionService { private PermissionMapper permissionMapper; public List<Permission> getPermissionsByRoleId(Integer roleId) { return permissionMapper.getPermissionsByRoleId(roleId); package com.ego.dao.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; @Mapper public interface UserMapper extends BaseMapper<User> { @Select("SELECT u.id,u.username,u.password,u.salt,u.age,u.email,u.address FROM t_user u WHERE u.username = #{username}") User findUserByUserName(String username); public interface RoleMapper extends BaseMapper<Role> { @Select("select r.id,r.name from t_role r left join t_user_role ur on ur.role_id = r.id where ur.user_id = #{userId}") List<Role> getRolesByUserId(Integer userId); public interface PermissionMapper extends BaseMapper<Permission> { @Select("select p.id,p.name,p.url from t_permission p left join t_role_permission rp on rp.permission_id = p.id where rp.role_id = #{roleId}") List<Permission> getPermissionsByRoleId(Integer roleId);
5.實(shí)現(xiàn)SaltUtil和ApplicationContextUtil兩個工具類
package com.ego.utils; import java.util.Random; /** * @author 袁夢達(dá) 2019012364 */ public class SaltUtil { 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(); } } import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; @Component public class ApplicationContextUtil implements ApplicationContextAware { public static ApplicationContext context; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.context = applicationContext; /** * 根據(jù)工廠中的類名獲取類實(shí)例 */ public static Object getBean(String beanName){ return context.getBean(beanName);
6.實(shí)現(xiàn)核心Shiro
package com.ego.utils; import java.util.Random; /** * @author 袁夢達(dá) 2019012364 */ public class SaltUtil { 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(); } } package com.ego.utils; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; /** * @author 袁夢達(dá) 2019012364 */ @Component public class ApplicationContextUtil implements ApplicationContextAware { public static ApplicationContext context; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.context = applicationContext; } /** * 根據(jù)工廠中的類名獲取類實(shí)例 */ public static Object getBean(String beanName){ return context.getBean(beanName); } }
7.實(shí)現(xiàn)Redis分布式緩存
package com.ego.shiro; import com.ego.shiro.cache.RedisCacheManager; 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; import java.util.Map; /** * @author 袁夢達(dá) 2019012364 */ @Configuration public class ShiroConfiguration { //1.創(chuàng)建shiroFilter //負(fù)責(zé)攔截所有請求 @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //給filter設(shè)置安全管理器 shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager); //配置系統(tǒng)受限資源 //配置系統(tǒng)公共資源 Map<String,String> map = new HashMap<String,String>(); map.put("/user/login", "anon"); map.put("/user/register","anon"); map.put("/register.jsp","anon"); map.put("/index.jsp","authc");//authc 請求這個資源需要認(rèn)證和授權(quán) //默認(rèn)認(rèn)證界面路徑 shiroFilterFactoryBean.setLoginUrl("/login.jsp"); shiroFilterFactoryBean.setFilterChainDefinitionMap(map); return shiroFilterFactoryBean; } //2.創(chuàng)建安全管理器 public DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm){ DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(); //給安全管理器設(shè)置 defaultWebSecurityManager.setRealm(realm); return defaultWebSecurityManager; //3.創(chuàng)建自定義realm public Realm getRealm(){ CustomerRealm customerRealm = new CustomerRealm(); // 設(shè)置密碼匹配器 HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); // 設(shè)置加密方式 credentialsMatcher.setHashAlgorithmName(ShiroConstant.HASH_ALGORITHM_NAME.MD5); // 設(shè)置散列次數(shù) credentialsMatcher.setHashIterations(ShiroConstant.HASH_ITERATORS); customerRealm.setCredentialsMatcher(credentialsMatcher); // 設(shè)置緩存管理器 customerRealm.setCacheManager(new RedisCacheManager()); // 開啟全局緩存 customerRealm.setCachingEnabled(true); // 開啟認(rèn)證緩存并指定緩存名稱 customerRealm.setAuthenticationCachingEnabled(true); customerRealm.setAuthenticationCacheName("authenticationCache"); // 開啟授權(quán)緩存并指定緩存名稱 customerRealm.setAuthorizationCachingEnabled(true); customerRealm.setAuthorizationCacheName("authorizationCache"); return customerRealm; } public class ShiroConstant { /** 隨機(jī)鹽的位數(shù) **/ public static final int SALT_LENGTH = 8; /** hash的散列次數(shù) **/ public static final int HASH_ITERATORS = 1024; public interface HASH_ALGORITHM_NAME { String MD5 = "MD5"; import com.ego.pojo.Permission; import com.ego.pojo.Role; import com.ego.pojo.User; import com.ego.service.PermissionService; import com.ego.service.RoleService; import com.ego.service.UserService; import com.ego.utils.ApplicationContextUtil; 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.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import java.util.List; public class CustomerRealm extends AuthorizingRealm { //授權(quán) @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // 獲取主身份信息 String principal = (String) principals.getPrimaryPrincipal(); // 根據(jù)主身份信息獲取角色信息 UserService userService = (UserService) ApplicationContextUtil.getBean("userService"); User user = userService.findUserByUserName(principal); RoleService roleService = (RoleService) ApplicationContextUtil.getBean("roleService"); List<Role> roles = roleService.getRolesByUserId(user.getId()); if(!CollectionUtils.isEmpty(roles)){ SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); roles.forEach(role -> { simpleAuthorizationInfo.addRole(role.getName()); PermissionService permissionService = (PermissionService) ApplicationContextUtil.getBean("permissionService"); List<Permission> permissions = permissionService.getPermissionsByRoleId(role.getId()); if(!CollectionUtils.isEmpty(permissions)){ permissions.forEach(permission -> { simpleAuthorizationInfo.addStringPermission(permission.getName()); }); } }); return simpleAuthorizationInfo; } return null; //認(rèn)證 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String principal = (String) token.getPrincipal(); if(!ObjectUtils.isEmpty(user)){ return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(), new CustomerByteSource(user.getSalt()),this.getName()); 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; //自定義salt實(shí)現(xiàn) 實(shí)現(xiàn)序列化接口 public class CustomerByteSource implements ByteSource, Serializable { private byte[] bytes; private String cachedHex; private String cachedBase64; public CustomerByteSource() { public CustomerByteSource(byte[] bytes) { this.bytes = bytes; public CustomerByteSource(char[] chars) { this.bytes = CodecSupport.toBytes(chars); public CustomerByteSource(String string) { this.bytes = CodecSupport.toBytes(string); public CustomerByteSource(ByteSource source) { this.bytes = source.getBytes(); public CustomerByteSource(File file) { this.bytes = (new CustomerByteSource.BytesHelper()).getBytes(file); public CustomerByteSource(InputStream stream) { this.bytes = (new CustomerByteSource.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);
到此這篇關(guān)于SpringBoot整合Shiro和Redis的文章就介紹到這了,更多相關(guān)SpringBoot整合Shiro和Redis內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
web.xml中servlet, bean, filter, listenr 加載順序_動力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了web.xml中servlet, bean, filter, listenr 加載順序,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08Ribbon負(fù)載均衡服務(wù)調(diào)用的示例詳解
Rbbo其實(shí)就是一個軟負(fù)載均衡的客戶端組件,他可以和其他所需請求的客戶端結(jié)合使用,這篇文章主要介紹了Ribbon負(fù)載均衡服務(wù)調(diào)用案例代碼,需要的朋友可以參考下2023-01-01Java多線程之并發(fā)編程的基石CAS機(jī)制詳解
這篇文章主要介紹了java并發(fā)編程之cas詳解,涉及cas使用場景和cas用作原子操作等內(nèi)容,具有一定參考價值,需要的朋友可以了解下2021-09-09Java中final,finally,finalize三個關(guān)鍵字的區(qū)別_動力節(jié)點(diǎn)Java學(xué)院整理
這篇文章給大家收集整理了有關(guān)java中final,finally,finalize三個關(guān)鍵字的區(qū)別介紹,非常不錯,具有參考借鑒價值,需要的的朋友參考下吧2017-04-04