一.導入依賴包

<!--spring boot 默認lettuce連接redis的技術--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!--郵件--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> <!--jdbc依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!--前端模板引擎依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!--springmvc--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web-services</artifactId> </dependency> <!--mybatis依賴--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.5</version> </dependency> <!--熱部署依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <!--mysql數據庫依賴--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!--簡化實體類依賴(set/get)--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!--單元測試依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- 分頁插件 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.5</version> </dependency> <!-- SpringBoot - MyBatis 逆向工程 --> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.2</version> <scope>runtime</scope> <optional>true</optional> </dependency> <!--EXCEL--> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.0.1</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.0.1</version> </dependency> <dependency> <groupId>net.oschina.likaixuan</groupId> <artifactId>excelutil</artifactId> <version>2.0.2</version> </dependency> <!--對象池--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <!--連接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.0</version> </dependency> <!-- fastjson阿里巴巴jSON處理器 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.13</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- shiro --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.4.0</version> </dependency> <!--thymeleaf對shiro擴展的依賴--> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency> <!--jedis依賴包--> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> <!--redisson--> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.5.4</version> </dependency> <!-- shiro+redis緩存插件 --> <dependency> <groupId>org.crazycake</groupId> <artifactId>shiro-redis</artifactId> <version>2.4.2.1-RELEASE</version> </dependency> <!-- 整合jsp所需依賴,要是添加了thymeleaf似乎會出問題--> <!--<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> </dependency>--> <!--jstl--> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency>
二.添加配置

#tomcat啟動端口 server.port=9090 #server.servlet.context-path=/ #自動重啟 spring.devtools.restart.enabled=true #添加額外監聽的路徑 #spring.devtools.restart.additional-paths=src/main/ #添加忽略目錄(排除的路徑) #spring.devtools.restart.exclude=/excludepath/ #實時刷新(通知瀏覽器實時刷新,要下插件) spring.devtools.livereload.enabled=true #mysql配置 spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://xx.xx.xx.xx:3306/xxx?useUnicode=true&characterEncoding=utf8 spring.datasource.username = xxx spring.datasource.password = xxxx spring.datasource.max-active=20 spring.datasource.max-idle=8 spring.datasource.min-idle=8 spring.datasource.initial-size=10 #mybatis #把數據庫字段的下划線轉換成實體類中的駝峰式命名 mybatis.configuration.map-underscore-to-camel-case=true #mybatis表映射文件目錄 mybatis.mapper-locations=classpath:mapper/*.xml #springmvc spring.mvc.view.prefix=/WEB-INF/views/ spring.mvc.view.suffix=.jsp #配置分頁插件pagehelper pagehelper.helperDialect=mysql pagehelper.reasonable=true pagehelper.supportMethodsArguments=true pagehelper.params.count=countSql #禁用thymeleaf緩存 spring.thymeleaf.cache=false #配置連接池 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource #druid監控配置 spring.datasource.filters=stat,wall,log4j spring.datasource.dbcp2.min-idle=5 #初始化提供的連接數 spring.datasource.dbcp2.initial-size=5 #最大的連接數 spring.datasource.dbcp2.max-total=5 #等待連接獲取的最大超時時間 spring.datasource.dbcp2.max-wait-millis=200 ##rabbitMQ #spring.rabbitmq.host=xx.xx.xx.xx #spring.rabbitmq.port=5672 #spring.rabbitmq.username=user #spring.rabbitmq.password=user ##redis #spring.redis.host=xx.xx.xx.xx #spring.redis.port=6379 #spring.redis.password=xxx #spring.redis.timeout=1000ms ##lettuce最大連接數 #spring.redis.lettuce.pool.max-active=8 ##連接池最大阻塞時間(-1表示沒有限制 #spring.redis.lettuce.pool.max-wait=-1ms ##最大空閑連接 #spring.redis.lettuce.pool.max-idle=8 ##最小空閑連接 #spring.redis.lettuce.pool.min-idle=0 # #logging.level.com.seecen=debug
由於springboot還沒集成shiro的properties所以要添加配置類,配置類如下(添加配置類之前最好先自定義Realm)
自定義Realm
package com.taotao.shiro; import com.taotao.pojo.User; import com.taotao.service.UserService; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.crypto.hash.Md5Hash; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.ByteSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.HashSet; import java.util.Set; /** * Author: TaoTao 2019/9/14 */ @Component public class UserRealm extends AuthorizingRealm { private static Logger logger = LoggerFactory.getLogger(UserRealm.class); @Autowired private UserService userService; /** * 驗證身份信息 * @param token * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { /** * 驗證用戶名步驟 * 1.獲取令牌中的用戶名 * 2.根據用戶名去查詢是否有該用戶 * a.有用戶存在 * b.沒有,直接拋出異常 * 3.返回一個驗證用戶名和密碼的類對象(封裝了md5加密的驗證方式) */ logger.info("---------------- 執行 Shiro 憑證認證 ----------------------"); String name = (String) token.getPrincipal(); // 從數據庫獲取對應用戶名密碼的用戶 User userInfo = userService.findUserByNames(name); if (userInfo != null) { // 用戶為禁用狀態 if (userInfo.getuState() != 0) { throw new DisabledAccountException("賬戶已被禁用!"); } logger.info("---------------- Shiro 憑證認證成功 ----------------------"); //md5加密再加鹽 //根據表單數據和加密字符串和鹽值進行比較驗證 SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo( name, //用戶 userInfo.getuPwd(), //密碼 ByteSource.Util.bytes(userInfo.getuSal()),//鹽值 getName() //realm name ); // 返回給安全管理器,由 securityManager 比對密碼的正確性 return authenticationInfo; } throw new UnknownAccountException(); } /** * 獲取操作權限 * @param principals * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { logger.info("---------------- 執行 Shiro 權限獲取 ---------------------"); //給資源進行授權 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //到數據庫查詢當前登錄用戶的授權字符串 //獲取當前登錄用戶 Subject subject = SecurityUtils.getSubject(); User user = (User) subject.getPrincipal(); // User dbUser = userService.find info.addStringPermission(null); logger.info("---------------- Shiro 權限獲取成功 ----------------------"); return info; /* String username = (String) principals.getPrimaryPrincipal(); //持久化操作:根據用戶名獲取角色信息和權限信息 //role: admin manage perms:user:create user :update 模塊:權限 Set<String> permissionList = new HashSet<>(); permissionList.add("user:list"); permissionList.add("user:create"); permissionList.add("user:update"); Set<String> roleList = new HashSet<>(); roleList.add("admin"); roleList.add("manager"); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); authorizationInfo.setRoles(roleList); authorizationInfo.setStringPermissions(permissionList); return authorizationInfo;*/ } } }
添加配置
package com.taotao.shiro; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.LinkedHashMap; import java.util.Map; /** * Author: TaoTao 2019/9/18 */ @Configuration public class ShiroConfig { /** * Filter工廠 * @param securityManager * @return */ @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){ ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //設置安全管理器 shiroFilterFactoryBean.setSecurityManager(securityManager); Map<String,String> filterMap = new LinkedHashMap<String, String>(); filterMap.put("/user/login","anon"); //指定路徑放行 filterMap.put("/user/loginVer","anon"); //設置為登錄跳轉的頁面 shiroFilterFactoryBean.setLoginUrl("/user/login"); //設置未授權跳轉頁面 shiroFilterFactoryBean.setUnauthorizedUrl("/user/noAuth"); //授權過濾 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); return shiroFilterFactoryBean; } /** * 密碼校驗規則HashedCredentialsMatcher * 這個類是為了對密碼進行編碼的 , * 防止密碼在數據庫里明碼保存 , 當然在登陸認證的時候 , * 這個類也負責對form里輸入的密碼進行編碼 * 處理認證匹配處理器:如果自定義需要實現繼承HashedCredentialsMatcher */ @Bean public HashedCredentialsMatcher hashedCredentialsMatcher(){ HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); // 使用md5 算法進行加密 hashedCredentialsMatcher.setHashAlgorithmName("md5"); // 設置散列次數: 加密次數(這個地方沒有鹽值也不會影響密碼對比) hashedCredentialsMatcher.setHashIterations(3); return hashedCredentialsMatcher; } /** * 自定義Realm */ @Bean(name="userRealms") public UserRealm getRealm(){ UserRealm userRealm = new UserRealm(); //配置加密方式(不然登錄失敗) userRealm.setCredentialsMatcher(hashedCredentialsMatcher()); return userRealm; } /** * 安全管家 */ @Bean(name = "securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealms") UserRealm userRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //關聯realm securityManager.setRealm(userRealm); return securityManager; } /** * 配置ShiroDialect ,用於thymeleaf和shiro標簽配合使用 * @return */ @Bean public ShiroDialect getShiroDialect(){ return new ShiroDialect(); } }
MD5加密加鹽
public static void main(String[] args) { //第一:把用戶的密碼通過md5算法加密 String password = "uuu"; // String md5String = new Md5Hash(password).toString();//不可逆加密算法 // System.out.println("原密碼:"+password); // System.out.println("md5加密的密碼:"+md5String); // //注冊,保存加密后的值 // //登錄驗證 把表單值動態加密再進行比較uuu // //第二種:加密同時加點鹽 // md5String = new Md5Hash(password,"abc").toString(); // System.out.println("md5加密且加鹽后的密碼:"+md5String); //第三種:加密次數 增加破解成本 String md5String; md5String = new Md5Hash("aaa","9734983ae2c939da48d8bc738d34ffb2",3).toString(); System.out.println("md5加密且加鹽,還加加密次數后的密碼:"+md5String); // //第四種:隨機鹽值,配合加密次數 //// String sal = getRandomString(); // md5String = new Md5Hash(password,"abc",3).toString(); // System.out.println("md5加密且隨機顏值,還加加密次數后的密碼:"+md5String);
總結
在搭建和權限這塊基本沒什么問題,我所出現的問題是,將密碼加密存入數據庫后,用戶登入失敗,在查詢資料后發現沒有添加 HashedCredentialsMatcher 配置,
然后一直在糾結數據庫中的密碼使用了鹽值進行加密,然后HashedCredentialsMatcher 中並沒有添加鹽值,而且在該配置類中修改加密次數也可以登入成功(難道這個配置只是在說我加密了哦,求大佬指點)