SpringBootの基本-権限管理1

権限管理

権限管理は、特定のユーザーに特定のインターフェイスの使用権限を割り当てることに他なりません。

データベースを作成する

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='用户测试表';

プロジェクトを作成する

    <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;
    }
}
  • ユーザーエンティティクラスの作成
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();
}
  • マッパーディレクトリに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();
    }
}

インターセプターを実装する(トークンウェイ

  • インターセプターを作成します。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();
    }
}

[]ログインに成功すると、すべてのメソッドインターフェイスを呼び出すことができ、権限制限を実装できなくなります。

権限の割り当て(方法1

  • データベースはメニュー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);
}
  • マッパーディレクトリに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);
    }
}
  • ユーザーエンティティクラスの編集
@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ファイルです。構成を適切に変更することで実行できます。

おすすめ

転載: blog.csdn.net/weixin_46899412/article/details/123699326