SpringBoot整合Shiro
SpringBoot整合Shiro
介绍
Shiro和SpringSecurity一样是一个安全框架,使用Shiro可以用在JavaSE环境下,也可以用在JavaEE环境,Shiro可以完成:认证、授权、加密、会话管理、与Web集成、缓存等
三个核心组件:Subject, SecurityManager 和 Realms
-
Subject:即“当前操作用户”。
Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
-
SecurityManager:它是Shiro 框架的核心,典型的Facade 模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
-
Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登
录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
整合SpringBoot
-
创建SpringBoot项目,勾选web
-
添加依赖
<!--shiro安全管理--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.7.1</version> </dependency> <!-- Thymeleaf依赖 --> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-java8time</artifactId> </dependency> <!--thymeleaf依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
-
创建html页面
index
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>首页</h1> <hr> <p th:text="${msg}"></p> <hr> <a th:href="@{/user/add}">add</a> | <a th:href="@{/user/add}">update</a> </body> </html>
login
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>登入</h1> <p th:text="${msg}" style="color:#ff0000"></p> <form th:action="@{/login}"> <p>用户名:<input type="text" name="username"></p> <p>密码:<input type="password" name="password"></p> <p><input type="submit"></p> </form> </body> </html>
add
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>add</h1> </body> </html>
update
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>update</h1> </body> </html>
-
controller
package com.sheep.controller; 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.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class MyController { @RequestMapping({"/","/index"}) public String toIndex(Model model){ model.addAttribute("msg","hello,shiro"); return "index"; } @RequestMapping("/user/add") public String add(){ return "user/add"; } @RequestMapping("/user/update") public String update(){ return "user/update"; } @RequestMapping("/toLogin") public String toLogin(){ return "login"; } @RequestMapping("/login") public String login(String username,String password,Model model){ /*获取当前用户*/ Subject subject = SecurityUtils.getSubject(); /*封装用户的登入数据*/ UsernamePasswordToken token = new UsernamePasswordToken(username, password); /*执行登入的方法,如果没有异常说明ok,捕获异常*/ try { subject.login(token); return "index"; } catch (UnknownAccountException e) { model.addAttribute("msg","用户名为空!!!"); return "login"; } catch (IncorrectCredentialsException e){ model.addAttribute("msg","密码为空!!!"); return "login"; } } @RequestMapping("/noauth") @ResponseBody public String unauthorized(){ return "未经授权无法访问此页面!!!"; } }
-
要使用shiro需要自定义Realm的授权和认证
package com.sheep.config; import com.sheep.pojo.User; import com.sheep.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.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; import org.springframework.beans.factory.annotation.Autowired; /*自定义UserRealm*/ public class UserRealm extends AuthorizingRealm { @Autowired UserService userService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("执行了=>授权(doGetAuthorizationInfo)"); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //给所有人添加user:add权限 info.addStringPermission("user:add"); return info; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("执行了=>认证(doGetAuthenticationInfo)"); /* * 用户名、密码、数据库中取 * */ /* * 自定义数据库 * */ String name="root"; String password="123456"; UsernamePasswordToken userToken = (UsernamePasswordToken) token; if(!userToken.getUsername().equals(name)){ return null;/*用户名错误,shiro自动抛出异常;密码认证shiro自动认证*/ } /*密码认证,Shiro会自动密码认证*/ return new SimpleAuthenticationInfo("",password,""); } }
-
shiro配置类
package com.sheep.config; 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; @Configuration public class ShiroConfig { /** * 1、创建自定义的realm对象 * 2、DafaultWebSecurityManager * 3、ShiroFilterFactoryBean * */ /*自定义的realm对象*/ @Bean public UserRealm userRealm(){ return new UserRealm(); } /*DafaultWebSecurityManager*/ @Bean public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //关联UserRealm securityManager.setRealm(userRealm); return securityManager; } /*ShiroFilterFactoryBean*/ @Bean public ShiroFilterFactoryBean getsShiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); //过滤请求 //设置安全管理器 bean.setSecurityManager(defaultWebSecurityManager); /*添加shiro的内置过滤器*/ /* * anno:无需认证可以访问 * authc:必须认证才能访问 * user:必须拥有记住我功能才能访问 * perms:拥有对某个资源的权限才能访问 * role:拥有某个角色权限才能访问 * */ Map<String, String> filterMap = new LinkedHashMap<>(); //授权 filterMap.put("/user/add","perms[user:add]"); //方法一 //filterMap.put("/user/add","authc"); //filterMap.put("/user/update","authc"); //方法二 filterMap.put("/user/*","authc"); bean.setFilterChainDefinitionMap(filterMap); /*设置登入请求*/ bean.setLoginUrl("/toLogin"); /*设置未授权页面*/ bean.setUnauthorizedUrl("/noauth"); return bean; } }
-
测试
整合MyBatis
-
导入要整合MyBatis的依赖
<!--简化实体类--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!--整合mybatis--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.6</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency>
-
创建表
+----------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+-------------+------+-----+---------+----------------+ | id | int | NO | PRI | NULL | auto_increment | | username | varchar(5) | YES | | NULL | | | password | varchar(6) | YES | | NULL | | | perms | varchar(20) | YES | | NULL | | +----------+-------------+------+-----+---------+----------------+
-
创建表对应的实体类
package com.sheep.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class User { private int id; private String username; private String password; private String perms; }
-
创建接口
package com.sheep.mapper; import com.sheep.pojo.User; import org.apache.ibatis.annotations.Mapper; import org.springframework.stereotype.Repository; @Mapper @Repository public interface UserMapper { public User queryUserByName(String username); }
-
service层接口
package com.sheep.service; import com.sheep.pojo.User; public interface UserService { public User queryUserByName(String username); }
-
service实现接口
package com.sheep.service; import com.sheep.mapper.UserMapper; import com.sheep.pojo.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserServiceImpl implements UserService { @Autowired UserMapper userMapper; @Override public User queryUserByName(String username) { return userMapper.queryUserByName(username); } }
-
测试连接数据库是否成功
package com.sheep; import com.sheep.service.UserServiceImpl; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest class DemoApplicationTests { @Autowired UserServiceImpl userService; @Test void contextLoads() { System.out.println(userService.queryUserByName("root")); } }
-
在resources文件夹下创建mapper.XML文件
<mapper namespace="com.sheep.mapper.UserMapper"> <select id="queryUserByName" parameterType="String" resultType="com.sheep.pojo.User"> select * from user where username = #{username} </select> </mapper>
-
application.properties配置连接数据库信息
# 配置数据库信息 spring.datasource.username=root spring.datasource.password=123321 spring.datasource.url=jdbc:mysql://localhost:3306/junit?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.type=com.alibaba.druid.pool.DruidDataSource # mybatis配置文件 mybatis.type-aliases-package=com.sheep.pojo mybatis.mapper-locations=classpath:mapper/*.XML
-
在自定义的Realm中使用数据库数据判断
package com.sheep.config; import com.sheep.pojo.User; import com.sheep.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.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; import org.springframework.beans.factory.annotation.Autowired; /*自定义UserRealm*/ public class UserRealm extends AuthorizingRealm { @Autowired UserService userService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("执行了=>授权(doGetAuthorizationInfo)"); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //info.addStringPermission("user:add"); //获取当前对象 Subject subject = SecurityUtils.getSubject(); //获取user对象 User currentUser =(User) subject.getPrincipal(); //设置当前用户的权限 info.addStringPermission(currentUser.getPerms()); return info; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("执行了=>认证(doGetAuthenticationInfo)"); /* * 用户名、密码、数据库中取 * */ UsernamePasswordToken userToken = (UsernamePasswordToken) token; //连接数据库 User user = userService.queryUserByName(userToken.getUsername()); if(user==null){ //如果没有该用户返回null return null; } /* * 自定义数据库 * */ //String name="root"; //String password="123456"; //UsernamePasswordToken userToken = (UsernamePasswordToken) token; //if(!userToken.getUsername().equals(name)){ // return null;/*用户名错误,shiro自动抛出异常;密码认证shiro自动认证*/ //} /*密码认证,Shiro会自动密码认证*/ return new SimpleAuthenticationInfo("",user.getPassword(),""); } }
package com.sheep.config; 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; @Configuration public class ShiroConfig { /** * 1、创建realm对象 :自定义 * 2、DafaultWebSecurityManager * 3、ShiroFilterFactoryBean * */ @Bean public UserRealm userRealm(){ return new UserRealm(); } @Bean public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //关联UserRealm securityManager.setRealm(userRealm); return securityManager; } @Bean public ShiroFilterFactoryBean getsShiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); //过滤请求 //设置安全管理器 bean.setSecurityManager(defaultWebSecurityManager); /*添加shiro的内置过滤器*/ /* * anno:无需认证可以访问 * authc:必须认证才能访问 * user:必须拥有记住我功能才能访问 * perms:拥有对某个资源的权限才能访问 * role:拥有某个角色权限才能访问 * */ Map<String, String> filterMap = new LinkedHashMap<>(); //授权.如果未授权跳转到授权页面 filterMap.put("/user/add","perms[user:add]"); /* * 方法- * filterMap.put("/user/add","authc"); * filterMap.put("/user/update","authc"); * */ /*方法二*/ filterMap.put("/user/*","authc"); bean.setFilterChainDefinitionMap(filterMap); /*设置登入请求*/ bean.setLoginUrl("/toLogin"); /*设置未授权页面*/ bean.setUnauthorizedUrl("/noauth"); return bean; } }
运行测试
还历史以真诚,还生命以过程。 ——余秋雨