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
-
添加依赖
org.apache.shiro shiro-spring 1.7.1 org.thymeleaf.extras thymeleaf-extras-java8time org.springframework.boot spring-boot-starter-thymeleaf -
创建html页面
index
Title 首页
add | updatelogin
Title 登入
add
Title add
update
Title update
-
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
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的依赖
org.projectlombok lombok mysql mysql-connector-java log4j log4j 1.2.17 com.alibaba druid 1.2.6 org.mybatis.spring.boot mybatis-spring-boot-starter 2.1.4 -
创建表
+----------+-------------+------+-----+---------+----------------+ | 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文件
-
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
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; } } 运行测试