SpringBoot基础-权限管理1
SpringBoot授权管理,SpringBoot拦截器
·
权限管理
权限管理无非就是把某一个接口的使用权限赋给某一个用户。
创建数据库
CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL COMMENT '名字', `username` varchar(255) DEFAULT NULL, `password` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='用户测试表';
创建项目
- 创建SpringBoot项目
- 编辑pow.xml引入依赖
<dependencies> <!--SpringBoot核心--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--SpringMVC核心--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--Mybatis核心--> <!--<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.1</version> </dependency>--> <!--mybatis-plus核心--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!--lombok核心--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.14</version> </dependency> </dependencies>
- 编写application.yml文件
server: #tomcat端口 port: 8080 spring: #MySQL数据库配置 datasource: url: jdbc:mysql://localhost:3306/springboot_demo?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC username: root password: 20220101 driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #实体类路径 typeAliasesPackage: com.qcby.entity #mapper路径 mapperLocations: classpath:mapper/*.xml # 全局配置id自增 => global-config: db-config: id-type: auto
- 创建包,创建config.MybatisPlusConfig 类,配置mybatis-plus
@Configuration public class MybatisPlusConfig { // 最新版 @Bean // <bean id=""/> public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }
- 创建User实体类
package com.qcby.entity; @Data @TableName("user") public class User { private Long id; private String name; private String username; private String password; }
- 创建mapper.UserMapper接口,继承mybatis-plus的BaseMapper类
@Mapper public interface UserMapper extends BaseMapper<User> { public List<User> findAll(); }
- mapper目录下创建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.qcby.mapper.UserMapper"> <select id="findAll" resultType="com.qcby.entity.User"> select * from user </select> </mapper>
- 创建service.UserService接口,继承mybatis-plus的IService类
public interface UserService extends IService<User> { public List<User> findAll(); }
- 创建service.impl.UserServiceImpl类,继承ServiceImpl类,实现UserService接口
@Service public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService { @Resource private UserMapper userMapper; @Override public List<User> findAll(){ return this.userMapper.findAll(); } }
- 创建controller.UserController类
@RestController @RequestMapping("login") public class UserController { @Autowired private UserServiceImpl service; @RequestMapping("findAll") public List<User> findAll(){ return this.service.findAll(); } }
实现拦截器(token方式)
- 创建interceptor.LoginInterceptor 拦截器类
package com.qcby.interceptor; public class LoginInterceptor implements HandlerInterceptor { private Logger log = LoggerFactory.getLogger(getClass()); @Autowired private HttpSession httpSession; //Controller逻辑执行之前 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle...."); String uri = request.getRequestURI(); System.out.println("uri:"+ uri); if (!(handler instanceof HandlerMethod)) { return true; } String token=request.getHeader("qcby-token"); if (!TokenUtil.verify(token)) { // 未登录跳转到登录界面 response.sendRedirect("/login/login"); return false; }else { return true; } } //Controller逻辑执行完毕但是视图解析器还未进行解析之前 @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { System.out.println("postHandle...."); } //Controller逻辑和视图解析器执行完毕 @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { System.out.println("afterCompletion...."); } }
- 创建WebMvcConfig类,设置拦截路径
package com.qcby.config; @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor()) //拦截的路径(*所有) .addPathPatterns("/**") // 那些路径不拦截 .excludePathPatterns("/login/login","/error"); } @Bean public LoginInterceptor loginInterceptor(){ return new LoginInterceptor(); } }
- 创建token.TokenUtil类
package com.qcby.token; public class TokenUtil { private static Map<String, User> tokenMap=new HashMap<>(); public static String generateToken(User user){ String token= UUID.randomUUID().toString(); tokenMap.put(token,user); return token; } public static boolean verify(String token){ return tokenMap.containsKey(token); } public static User getUser(String token){ return tokenMap.get(token); } }
- 编写登录方法
package com.qcby.controller; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.qcby.entity.User; import com.qcby.service.impl.UserServiceImpl; import com.qcby.token.TokenUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpSession; import java.util.HashMap; import java.util.List; import java.util.Map; @RestController @RequestMapping("login") public class UserController { @Autowired private UserServiceImpl service; @Autowired private HttpSession session; @RequestMapping(value = "login",method = RequestMethod.GET) public Map<String,Object> login(User user){ Map<String,Object> map = new HashMap<>(); map.put("code",0); if(StringUtils.isEmpty(user.getUsername()) || StringUtils.isEmpty(user.getPassword()) ){ map.put("msg","用户或者密码为空!"); return map; } QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("username",user.getUsername()) .eq("password",user.getPassword()); User userDb = service.getOne(queryWrapper); if(userDb != null){ map.put("code",1); map.put("data",userDb); String token= TokenUtil.generateToken(userDb); map.put("qcby-token",token); }else{ map.put("msg","用户名或密码错误!"); } return map; } @GetMapping("findAll") public List<User> findAll(){ return this.service.findAll(); } }
【注意】 登录成功之后所有方法接口都可以被调用,无法实现权限限制。
权限分配(方法一)
- 数据库创建menu,ref_menu_user表:因为所有接口方法路径存放在数据库中
CREATE TABLE `menu` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, `url` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; CREATE TABLE `ref_menu_user` ( `user_id` bigint(20) NOT NULL, `menu_id` bigint(20) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
- 创建Menu实体类
package com.qcby.entity; @Data public class Menu { private Integer id; private String name; private String url; }
- 创建MenuMapper接口
package com.qcby.mapper; public interface MenuMapper { //根据id获取用户能使用的 接口方法路径 public Set<String> getUrlListById(@Param("id") Long id); }
- mapper目录下创建MenuMapper.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.qcby.mapper.MenuMapper"> <select id="getUrlListById" resultType="java.lang.String"> select url from menu left join ref_menu_user on menu.id=ref_menu_user.menu_id where ref_menu_user.user_id=#{id} </select> </mapper>
- 创建MenuService接口
public interface MenuService { public Set<String> getUrlListById(Long id); }
- 创建MenuServiceImpl类
@Service public class MenuServiceImpl implements MenuService { @Resource private MenuMapper menuMapper; public Set<String> getUrlListById(Long id){ return this.menuMapper.getUrlListById(id); } }
- 编辑User实体类
@Data @TableName("user") public class User { private Long id; private String name; private String username; private String password; @TableField(exist = false)//数据库查询时忽略 private Set<String> url;//去重存储 }
- 编辑UserController,编写getUrlListById方法,获取授权的方法路径存入User实体类的url属性里面
@RestController @RequestMapping("login") public class UserController { @Autowired private UserServiceImpl service; @Autowired private HttpSession session; @Autowired private MenuServiceImpl menuService; @RequestMapping(value = "login",method = RequestMethod.GET) public Map<String,Object> login(User user){ Map<String,Object> map = new HashMap<>(); map.put("code",0); if(StringUtils.isEmpty(user.getUsername()) || StringUtils.isEmpty(user.getPassword()) ){ map.put("msg","用户或者密码为空!"); return map; } QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("username",user.getUsername()) .eq("password",user.getPassword()); User userDb = service.getOne(queryWrapper); if(userDb != null){ map.put("code",1); map.put("data",userDb); String token= TokenUtil.generateToken(userDb); map.put("qcby-token",token); /* *重点在这里,把从数据库查询到的方法路径存到实体类的url中 */ Set<String> url=menuService.getUrlListById(userDb.getId()); userDb.setUrl(url); }else{ map.put("msg","用户名或密码错误!"); } return map; } @RequestMapping("getUrlListById") public Set<String> getUrlListById(Long id){ return this.menuService.getUrlListById(id); } @GetMapping("findAll") public IPage<User> findAll(Page<User> page){ return this.service.findAll(page); } }
- 编辑拦截器类(判断用户访问的路径是否被授权给此用户)
package com.qcby.interceptor; public class LoginInterceptor implements HandlerInterceptor { private Logger log = LoggerFactory.getLogger(getClass()); @Autowired private HttpSession httpSession; //Controller逻辑执行之前 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle...."); String uri = request.getRequestURI(); System.out.println("uri:"+ uri); if (!(handler instanceof HandlerMethod)) { return true; } String token=request.getHeader("qcby-token"); if (!TokenUtil.verify(token)) { // 未登录跳转到登录界面 response.sendRedirect("/login/login"); return false; }else { //登录成功 //验证身份 User user=TokenUtil.getUser(token); //获取实体类的url属性,被授权的方法路径 Set<String> url=user.getUrl(); //查看用户调用的方法是否在url集合里面 if(!url.contains(uri)) throw new Exception("权限不足"); return true; } } //Controller逻辑执行完毕但是视图解析器还未进行解析之前 @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { System.out.println("postHandle...."); } //Controller逻辑和视图解析器执行完毕 @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { System.out.println("afterCompletion...."); } }
【注意】 最后需要配置xxxapplication类
package com.qcby; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @MapperScan("com.qcby.mapper") @SpringBootApplication public class Demo0325Application { public static void main(String[] args) { SpringApplication.run(Demo0325Application.class, args); } }
源码
源码是本仓库中的demo0326文件 包括数据表,源码;适当更改配置即可运行。
更多推荐
已为社区贡献5条内容
所有评论(0)