Spring Boot整合Shiro完成認證,權限管理,MD5+salt加密
整合代碼如下
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.1.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.junwei</groupId>
<artifactId>springboot-shiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-shiro</name>
<description>Demo project for Spring Boot</description>
<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>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.28</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--thymel對shiro的擴展標籤 整合-->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
後端代碼
-
User.java
package com.junwei.springbootshiro.pojo; import lombok.*; import org.springframework.stereotype.Repository; /** * @Auther: wangjunwei * @Description: 用戶實體類 * @Date: Created in 16:18 2019/6/8 */ @Setter @Getter @NoArgsConstructor @AllArgsConstructor @ToString @Repository public class User { private int id; private String username; private String password; private String perms; }
-
UserMapper.java
package com.junwei.springbootshiro.mapper; import com.junwei.springbootshiro.pojo.User; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; /** * @Auther: wangjunwei * @Description: 用戶mapper層 * @Date: Created in 16:19 2019/6/8 */ @Mapper public interface UserMapper { User findUser(@Param("username") String username); User findById(@Param("id") Integer id); void toRegist(@Param("user") User user,@Param("perms") String perms); }
-
UserMapper.xml
<?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.junwei.springbootshiro.mapper.UserMapper"> <insert id="toRegist"> insert into user (username, password,perms) values (#{user.username},#{user.password}, #{perms}) </insert> <select id="findUser" resultType="com.junwei.springbootshiro.pojo.User"> select id,username,password from user where username = #{username} </select> <select id="findById" resultType="com.junwei.springbootshiro.pojo.User"> select id,username,password,perms from user where id=#{id} </select> </mapper>
-
UserService.java
package com.junwei.springbootshiro.service; import com.junwei.springbootshiro.mapper.UserMapper; import com.junwei.springbootshiro.pojo.User; import com.junwei.springbootshiro.utils.Salt; import org.apache.shiro.crypto.hash.Md5Hash; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @Auther: wangjunwei * @Description: 用戶業務邏輯層 * @Date: Created in 16:21 2019/6/8 */ @Service public class UserService { @Autowired private UserMapper userMapper; public User findUser(String username) { return userMapper.findUser(username); } public User findById(Integer id) { return userMapper.findById(id); } public void toRegist(User user) { //密碼加鹽 user.setPassword(new Md5Hash(user.getPassword(), Salt.addSalt).toString()); userMapper.toRegist(user,"user:none"); } }
-
ShiroConfig.java
package com.junwei.springbootshiro.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; /** * @Auther: wangjunwei * @Description: Shiro配置類 * @Date: Created in 10:34 2019/6/8 */ @Configuration public class ShiroConfig { /** * @param defaultWebSecurityManager 1 * @return : org.apache.shiro.spring.web.ShiroFilterFactoryBean * @Author: wangjunwei * @Date: Created in 10:57 2019/6/8 * @Description: 創建ShiroFilterFactoryBean */ @Bean(name = "shiroFilterFactoryBean") public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager" ) DefaultWebSecurityManager defaultWebSecurityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //設置安全管理器 shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager); //添加shiro內置過濾器 /* annon:表示可以匿名使用 authc:表示需要認證(登錄)才能使用,沒有參數 roles:參數可以寫多個,多個時必須加上雙引號,並且參數之間用逗號分隔 例如/admins/user/**=perms["user:add:*, user:modify:*"],當有多個參數時必須每個參數都通過才通過,想當於isPermitedAll()方法。 rest:根據請求的方法,相當於/admins/user/**=perms[user:method] ,其中method爲post,get,delete等。 port:當請求的url的端口不是8081是跳轉到schemal://serverName:8081?queryString, 其中schmal是協議http或https等,serverName是你訪問的host, 8081是url配置裏port的端口,queryString是你訪問的url裏的?後面的參數。 authcBasic:沒有參數表示httpBasic認證 ssl:表示安全的url請求,協議爲https user:當登入操作時不做檢查 perms:該資源必須授予權限纔可以訪問 */ Map<String, String> fMap = new LinkedHashMap<>(); //攔截頁面 fMap.put("/add", "authc"); fMap.put("/update", "authc"); //授權過濾器 //注意:當前授權攔截後,shiro會自動跳轉到未授權頁面 fMap.put("/add", "perms[user:add]"); fMap.put("/update", "perms[user:update]"); shiroFilterFactoryBean.setFilterChainDefinitionMap(fMap); //被攔截返回登錄頁面 shiroFilterFactoryBean.setLoginUrl("/login"); //設置未授權提示頁面 shiroFilterFactoryBean.setUnauthorizedUrl("/permission"); return shiroFilterFactoryBean; } /** * @param userRealm 1 * @return : org.apache.shiro.web.mgt.DefaultWebSecurityManager * @Author: wangjunwei * @Date: Created in 17:24 2019/6/14 * @Description: 創建SecurityManager */ @Bean(name = "defaultWebSecurityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) { DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(); //關聯Realm defaultWebSecurityManager.setRealm(userRealm); return defaultWebSecurityManager; } /** * @return : com.junwei.springbootshiro.shiro.UserRealm * @Author: wangjunwei * @Date: Created in 16:55 2019/6/14 * @Description: 創建Realm * 並設置加密規則 */ @Bean(name = "userRealm") public UserRealm getRealm(@Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher hashedCredentialsMatcher) { UserRealm userRealm = new UserRealm(); userRealm.setCredentialsMatcher(hashedCredentialsMatcher); return userRealm; } /** * @return : at.pollux.thymeleaf.shiro.dialect.ShiroDialect * @Author: wangjunwei * @Date: Created in 18:00 2019/6/15 * @Description: 配置ShiroDialect,用於thymeleaf和shiro標籤配合使用 */ @Bean public ShiroDialect getShiroDialect() { return new ShiroDialect(); } /** * @return : org.apache.shiro.authc.credential.HashedCredentialsMatcher * @Author: wangjunwei * @Date: Created in 19:14 2019/6/15 * @Description: 設置加密對象,加密規則 */ @Bean(name = "hashedCredentialsMatcher") public HashedCredentialsMatcher hashedCredentialsMatcher() { HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); //使用md5加密算法進行加密 hashedCredentialsMatcher.setHashAlgorithmName("md5"); //設置散列次數:加密次數 hashedCredentialsMatcher.setHashIterations(1); return hashedCredentialsMatcher; } }
-
UserRealm.java
package com.junwei.springbootshiro.shiro; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.junwei.springbootshiro.pojo.User; import com.junwei.springbootshiro.service.UserService; import com.junwei.springbootshiro.utils.Salt; 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.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.ByteSource; import org.springframework.beans.factory.annotation.Autowired; /** * @Auther: wangjunwei * @Description: 自定義Realm * @Date: Created in 16:17 2019/6/8 */ public class UserRealm extends AuthorizingRealm { @Autowired private UserService userService; /** * @param principalCollection 1 * @return : org.apache.shiro.authz.AuthorizationInfo * @Author: wangjunwei * @Date: Created in 16:53 2019/6/14 * @Description: 執行授權 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { //授權 System.out.println("授權"); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); //到數據庫查詢當前登錄用戶的授權字符串 //獲取當前登錄用戶 Subject subject = SecurityUtils.getSubject(); User user = (User) subject.getPrincipal(); User result = userService.findById(user.getId()); //授權 simpleAuthorizationInfo.addStringPermission(result.getPerms()); return simpleAuthorizationInfo; } /** * @param authenticationToken 1 * @return : org.apache.shiro.authc.AuthenticationInfo * @Author: wangjunwei * @Date: Created in 16:54 2019/6/14 * @Description: 執行認證 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("認證"); //shiro判斷邏輯 判斷用戶名和密碼 UsernamePasswordToken user = (UsernamePasswordToken) authenticationToken; User newUser = userService.findUser(user.getUsername()); if (newUser == null) { return null; } System.out.println(user.getPassword()); //加密加鹽認證 SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(newUser, newUser.getPassword(), ByteSource.Util.bytes(Salt.addSalt), getName()); return authenticationInfo; } }
-
Salt.java
package com.junwei.springbootshiro.utils; /** * @Auther: wangjunwei * @Description: 用戶加鹽 * @Date: Created in 18:51 2019/6/15 */ public class Salt { public static final String addSalt = "regist@^$*#!"; }
-
PageController.java
package com.junwei.springbootshiro.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; /** * @Auther: wangjunwei * @Description: 頁面跳轉controller * @Date: Created in 17:38 2019/6/14 */ @Controller public class PageController { @RequestMapping("/") public String toIndex(){ return "index"; } @RequestMapping("/{pageName}") public String toPage(@PathVariable String pageName){ return pageName; } }
-
UserController.java
package com.junwei.springbootshiro.controller; import com.junwei.springbootshiro.pojo.User; import com.junwei.springbootshiro.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.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; /** * @Auther: wangjunwei * @Description: 用戶controller層 * @Date: Created in 16:23 2019/6/8 */ @Controller public class UserController { @Autowired private UserService userService; @RequestMapping(value = "toLogin",method = RequestMethod.POST) public String toLogin(User user, Model model){ //shiro用戶認證 Subject subject = SecurityUtils.getSubject(); //封裝用戶數據 UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword()); try { subject.login(token); model.addAttribute("username",user.getUsername()); return "index"; }catch (UnknownAccountException e){ model.addAttribute("msg","用戶名不存在"); return "login"; }catch (IncorrectCredentialsException e){ model.addAttribute("msg","密碼錯誤"); return "login"; } } /** * @Author: wangjunwei * @Date: Created in 18:42 2019/6/15 * @Description: * 註銷功能 * @return : java.lang.String */ @RequestMapping("logout") public String logout(){ Subject subject = SecurityUtils.getSubject(); subject.logout(); return "index"; } /** * @Author: wangjunwei * @Date: Created in 18:46 2019/6/15 * @Description: 用戶註冊 * @param user 1 * @return : java.lang.String */ @RequestMapping(value = "toRegist",method = RequestMethod.POST) public String toRegist(User user){ userService.toRegist(user); return "index"; } }
配置文件application.properties
#spring集成Mybatis環境 別名掃描
mybatis.type-aliases-package=com.junwei.springbootshiro.pojo
#加載Mybatis配置文件
mybatis.mapper-locations = classpath:mapper/*Mapper.xml
spring.datasource.type = com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name= com.mysql.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/yjlg?useUnicode=true&characterEncoding=utf-8
spring.datasource.username = root
spring.datasource.password = 123
前臺代碼
-
index.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml" xmlns:shiro="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>首頁</title> </head> <body> <h1>首頁</h1> <!--驗證當前用戶是否爲“訪客”,即未登錄的用戶--> <p shiro:guest=""><a href="/login">請登錄</a></p> <p><a href="/regist">註冊</a></p> <p shiro:authenticated="">你好, <shiro:principal property="username" /><br/><a href="/logout">註銷</a></p> <a shiro:hasPermission="user:add" href="/add">添加</a> <a shiro:hasPermission="user:update" href="/update">修改</a> </body> </html>
-
login.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>登錄頁面</title> </head> <body> <h1>登錄頁面</h1> <form action="/toLogin" method="post"> <p> <span>用戶名:</span> <input type="text" name="username"> </p> <p> <span>密碼:</span> <input type="password" name="password"> </p> <input type="submit" value="登陸"> </form> <h3 th:text="${msg}"></h3> </body> </html>
-
regist.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用戶註冊</title> </head> <body> <h1>用戶註冊</h1> <form action="/toRegist" method="post"> <p>用戶名:<input type="text" name="username"></p> <p>密碼:<input type="password" name="password"></p> <input type="submit" value="註冊"> </form> </body> </html>
-
add.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用戶添加</title> </head> <body> <h1>用戶添加頁面</h1> </body> </html>
-
update.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用戶修改</title> </head> <body> <h1>用戶修改頁面</h1> </body> </html>
-
premission.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>未授權提示頁面</title> </head> <body> <h1>爲授權提示頁面</h1> </body> </html>