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>