springboot整合shiro简单使用(查询数据库)
shiro主要实现认证和授权的问题
认证确认用户身份,授权对用户访问资源的权限做控制
建表语句
CREATE TABLE `user` ( id INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键', `name` VARCHAR(255) COMMENT '用户名', `password` VARCHAR(255) COMMENT '密码' ) INSERT INTO `user`(`name`,`password`) VALUES('test','123456') CREATE TABLE `role` ( id INT(11) PRIMARY KEY AUTO_INCREMENT NOT NULL COMMENT '主键', role_name VARCHAR(255) DEFAULT NULL COMMENT '角色名称', user_id VARCHAR(255) DEFAULT NULL COMMENT '用户id' ) INSERT INTO `role`(role_name,user_id) VALUES('admin','1') CREATE TABLE permission ( id INT(11) PRIMARY KEY AUTO_INCREMENT NOT NULL COMMENT '主键', permission VARCHAR(255) DEFAULT NULL COMMENT '权限', role_id VARCHAR(255) DEFAULT NULL COMMENT '角色id' ) INSERT INTO permission(permission,role_id) VALUES ('create','1'), ('query','1')
代码部分
<?xml version="1.0" encoding="UTF-8"?>4.0.0 org.springframework.boot spring-boot-starter-parent 2.3.4.RELEASE com.java shiro-service 1.0-SNAPSHOT org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.apache.shiro shiro-spring 1.6.0 org.springframework.boot spring-boot-starter-aop org.projectlombok lombok true org.mybatis.spring.boot mybatis-spring-boot-starter 2.1.2 mysql mysql-connector-java 5.1.6 com.alibaba druid 1.1.4 org.springframework.boot spring-boot-starter-thymeleaf org.springframework.boot spring-boot-devtools runtime org.springframework.boot spring-boot-maven-plugin
server.port=8001 logging.level.com.java=debug logging.level.web=debug spring.devtools.add-properties=false spring.datasource.driver-class-name=com.mysql.jdbc.Driver #spring.datasource.url=jdbc:mysql://127.0.0.1:3306/spring_shiro?useUnicode=true&characterEncoding=utf-8&useSSL=false #spring.datasource.username=root #spring.datasource.password=root mybatis.mapper-locations=classpath:mapping/*.xml mybatis.configuration.map-underscore-to-camel-case=true spring.aop.proxy-target-class=true
<?xml version="1.0" encoding="UTF-8"?>INSERT INTO permission(permission,role_id) VALUES (#{item.permission},#{item.roleId})
<?xml version="1.0" encoding="UTF-8"?>
package com.java; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * @author yourheart * @Description * @create 2022-05-03 20:30 */ @SpringBootApplication public class ShiroApplication { public static void main(String[] args) { SpringApplication.run(ShiroApplication.class,args); } }
package com.java.bean; import lombok.Data; /** * @author yourheart * @Description * @create 2022-06-15 1:54 */ @Data public class Permission { private Integer id; private String permission; private Integer roleId; } package com.java.bean; import lombok.Data; /** * @author yourheart * @Description * @create 2021-09-17 23:54 */ @Data public class ResponseBean { /** * 状态码 */ private String code; /** * 返回值 */ private String msg; /** * 拓展字段 */ private Object extraInfo; } package com.java.bean; import lombok.Data; import java.util.List; /** * @author yourheart * @Description * @create 2022-06-15 1:55 */ @Data public class Role { private Integer id; private String roleName; private Integer userId; private Listpermissions; } package com.java.bean; import lombok.Data; import java.util.List; /** * @author yourheart * @Description * @create 2022-06-15 1:53 */ @Data public class User { private Integer id; private String name; private Integer password; private List roles; }
package com.java.mapper; import com.java.bean.Permission; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import java.util.List; /** * @author yourheart * @Description * @create 2022-06-25 8:37 */ @Mapper public interface PermissionMapper { @Select("SELECT permission FROM permission WHERE role_id=#{roleId}") ListfindPermission(Integer roleId); int addBatchPermission(List permissions); } package com.java.mapper; import com.java.bean.Role; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import java.util.List; /** * @author yourheart * @Description * @create 2022-06-25 8:37 */ @Mapper public interface RoleMapper { @Select("SELECT * FROM `role` r WHERE user_id =#{id}") List findRoleById(Integer id); @Insert("INSERT INTO `role`(role_name,user_id) VALUES(#{roleName},#{userId})") int addRole(Role role); } package com.java.mapper; import com.java.bean.User; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import java.util.List; import java.util.Map; /** * @author yourheart * @Description * @create 2022-06-25 8:10 */ @Mapper public interface UserMapper { @Select("SELECT * FROM `user` WHERE `name`=#{name}") User findByName(@Param("name") String name); @Select("SELECT COUNT(*) FROM `user` WHERE `name`=#{name} AND `password`=#{password}") int selectUserExists(User user); @Insert("INSERT INTO `user`(`name`,`password`) VALUES(#{name},#{password})") int addUser(User user); @Select("SELECT * FROM `user` WHERE id=#{id}") User findById(Integer id); @Select("SELECT a.`name`,a.`password`,b.`role_name`,c.`permission` \n" + "FROM `user` a INNER JOIN `role` b ON a.id=b.user_id INNER JOIN permission c ON b.id=c.role_id") List
package com.java.service; import com.java.bean.ResponseBean; import com.java.bean.User; public interface UserService { /** * 通过用户名查询用户的权限 * @param name * @return */ User getUserByName(String name); /** * 添加用户时默认给query权限 * @param user * @return */ ResponseBean addUser(User user); } package com.java.service.impl; import com.java.bean.Permission; import com.java.bean.ResponseBean; import com.java.bean.Role; import com.java.bean.User; import com.java.mapper.PermissionMapper; import com.java.mapper.RoleMapper; import com.java.mapper.UserMapper; import com.java.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; /** * @author yourheart * @Description * @create 2022-06-24 20:34 */ @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Autowired private RoleMapper roleMapper; @Autowired private PermissionMapper permissionMapper; /** * 通过用户名查询用户的权限 * * @param name * @return */ @Override public User getUserByName(String name) { User user = userMapper.findByName(name); ListroleByName = roleMapper.findRoleById(user.getId()); roleByName.forEach(role -> { List permissionList = permissionMapper.findPermission(role.getId()); role.setPermissions(permissionList); }); user.setRoles(roleByName); return user; } /** * 添加用户时默认给query权限 * * @param user * @return */ @Override public ResponseBean addUser(User user) { ResponseBean responseBean=new ResponseBean(); int selectUserExists = userMapper.selectUserExists(user); if (selectUserExists==1){ responseBean.setCode("-100"); responseBean.setMsg("用户已经存在"); return responseBean; } //入参需要用户名和密码 int addUser = userMapper.addUser(user); //通过用户名查询返回用户的id,向角色表中存放用户的角色和用户的id User byName = userMapper.findByName(user.getName()); Role role=new Role(); role.setRoleName("common"); role.setUserId(byName.getId()); int addRole = roleMapper.addRole(role); //查询角色的id,向权限表存放角色的权限和角色id List roleById = roleMapper.findRoleById(byName.getId()); roleById.forEach(r->{ Integer rId = r.getId(); List permissions=new ArrayList<>(); Permission permission=new Permission(); permission.setPermission("query"); permission.setRoleId(rId); permissions.add(permission); permissionMapper.addBatchPermission(permissions); }); responseBean.setCode("100"); responseBean.setMsg("用户添加成功"); return responseBean; } }
shiro权限控制部分
package com.java.config; import com.java.bean.Permission; import com.java.bean.Role; import com.java.bean.User; import com.java.service.UserService; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; 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.springframework.beans.factory.annotation.Autowired; /** * @author yourheart * @Description 实现AuthorizingRealm接口用户用户认证 * @create 2022-06-15 1:56 */ @Slf4j public class MyShiroRealm extends AuthorizingRealm { @Autowired private UserService userService; /** * 角色权限和对应权限添加 * * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { //获取登录用户名 String name = (String) principalCollection.getPrimaryPrincipal(); log.info("【角色权限和对应权限添加】name:{}", name); //查询用户名称 User user = userService.getUserByName(name); log.info("【角色权限和对应权限添加】user:{}", user); //添加角色和权限 SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); for (Role role : user.getRoles()) { //添加角色 simpleAuthorizationInfo.addRole(role.getRoleName()); for (Permission permission : role.getPermissions()) { //添加权限 simpleAuthorizationInfo.addStringPermission(permission.getPermission()); } } return simpleAuthorizationInfo; } /** * 用户认证 * * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //加这一步的目的是在Post请求的时候会先进认证,然后在到请求 log.info("【用户认证】authenticationToken.getPrincipal():{}", authenticationToken.getPrincipal()); if (authenticationToken.getPrincipal() == null) { return null; } //获取用户信息 String name = authenticationToken.getPrincipal().toString(); log.info("【用户认证】name:{}", name); User user = userService.getUserByName(name); log.info("【用户认证】user:{}", user); if (user == null) { //这里返回后会报出对应异常 return null; } else { //这里验证authenticationToken和simpleAuthenticationInfo的信息 SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name, user.getPassword().toString(), getName()); return simpleAuthenticationInfo; } } } package com.java.config; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.HashMap; import java.util.Map; /** * @author yourheart * @Description * @create 2022-06-15 1:58 */ @Configuration @Slf4j public class ShiroConfiguration { /** * 将自己的验证方式加入容器 * * @return */ @Bean public MyShiroRealm myShiroRealm() { MyShiroRealm myShiroRealm = new MyShiroRealm(); return myShiroRealm; } /** * 权限管理,配置主要是Realm的管理认证 * * @return */ @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myShiroRealm()); return securityManager; } /** * Filter工厂,设置对应的过滤条件和跳转条件 * * @param securityManager * @return */ @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); Mapmap = new HashMap (); //登出 map.put("/logout", "logout"); /** * Shiro内置过滤器,能够实现拦截器相关的拦截器 * 经常使用的过滤器: * anon:无需认证(登陆)能够访问 * authc:必须认证才能够访问 * user:若是使用rememberMe的功能能够直接访问 * perms:该资源必须获得资源权限才能够访问 * role:该资源必须获得角色权限才能够访问 **/ //对所有用户认证 map.put("/**", "authc"); map.put("/re", "anon"); //登录 shiroFilterFactoryBean.setLoginUrl("/login"); //首页 shiroFilterFactoryBean.setSuccessUrl("/index"); //错误页面,认证不通过跳转 shiroFilterFactoryBean.setUnauthorizedUrl("/error"); shiroFilterFactoryBean.setFilterChainDefinitionMap(map); return shiroFilterFactoryBean; } /** * 加入注解的使用,不加入这个注解不生效 * * @param securityManager * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } }
package com.java.controller.front; import com.java.bean.Role; import com.java.bean.User; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; /** * @author yourheart * @Description * @create 2022-06-15 2:11 */ @RestController @Slf4j public class TestController { @PostMapping("/login") public String login(@RequestBody User user) { if (StringUtils.isEmpty(user.getName()) || StringUtils.isEmpty(user.getPassword())) { return "请输入用户名和密码!"; } //用户认证信息 Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken( user.getName(), String.valueOf(user.getPassword()) ); try { //进行验证,这里可以捕获异常,然后返回对应信息 subject.login(usernamePasswordToken); } catch (UnknownAccountException e) { log.error("用户名不存在!", e); return "用户名不存在!"; } catch (AuthenticationException e) { log.error("账号或密码错误!", e); return "账号或密码错误!"; } catch (AuthorizationException e) { log.error("没有权限!", e); return "没有权限"; } return "login success"; } /** * 用户登出 * @return */ @RequestMapping("/loginOut") public String loginOut(){ Subject subject = SecurityUtils.getSubject(); subject.logout(); return "退出成功"; } @RequiresPermissions("query") @RequestMapping(value = "/index") @ResponseBody public String index(){ return "进入主页"; } @RequiresPermissions("create") @GetMapping("/add") public String add() { return "add success!"; } @RequestMapping(value = "/re") @ResponseBody public String re(){ return "进入注册页面"; } @RequestMapping(value = "/log") @ResponseBody public String log(){ return "进入日志页面"; } }
附上测试地址
http://127.0.0.1:8001/login { "name":"qiuxie", "password":"123" } http://127.0.0.1:8001/index http://127.0.0.1:8001/add 用户登出 http://127.0.0.1:8001/loginOut