springboot+mybatis+sucurity

Mybatis Plus 是一个非常流行的 ORM 框架,可以帮助我们在 Spring 中更方便地访问数据库。在配合 Spring Security 使用时,我们可以使用 Mybatis Plus 来定义数据访问层(DAO),使用 Spring Boot 的自动配置功能来配置 Mybatis Plus 和 Spring Security,从而实现用户认证和授权的功能。

下面是一个使用 Mybatis Plus 和 Spring Security 的示例:

1.创建用户表

首先,我们需要在数据库中创建用户表,作为存储用户信息和凭证的表。在本例中,我们创建一个名为 sys_user 的表,包含了用户 ID、用户名、密码和是否启用等字段。

CREATE TABLE `sys_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `username` varchar(50) NOT NULL COMMENT '用户名',
  `password` varchar(100) NOT NULL COMMENT '密码',
  `enabled` tinyint(1) NOT NULL DEFAULT 1 COMMENT '是否启用:0-禁用,1-启用',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_username` (`username`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户信息表';

2.添加 Mybatis Plus 和 Spring Security 的依赖

在 Maven 中添加 Mybatis Plus 和 Spring Security 的依赖:




    com.baomidou
    mybatis-plus-boot-starter
    3.4.2



    org.springframework.boot
    spring-boot-starter-security
    2.5.2

3.配置 Mybatis Plus 和 Spring Security

在 Spring Boot 的配置文件中,添加如下配置:

# application.yml

server:
  port: 8080

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
  security:
    user:
      name: admin
      password: password
  mvc:
    # 去掉默认的 favicon.ico
    favicon:
      enabled: false

mybatis-plus:
  configuration:
    # 开启驼峰命名规则,即支持Java的驼峰命名法。
    map-underscore-to-camel-case: true
  # 扫描 Mapper 接口,注意:这里需要换成自己 DTO 的包。
  mapper-locations: classpath*:/mapper/**Mapper.xml

在上述代码中,我们配置了数据源、Spring Security 的用户信息(用于登录验证)、Mybatis Plus 的配置和 Mapper 接口的扫描位置。需要注意的是,这里的 mapper-locations 是 Mapper XML 文件的位置,需要根据实际情况进行配置。

4.定义 Mapper 接口

在 Mybatis Plus 中,可以使用 Mapper 接口来访问数据库。首先,需要定义一个用于表示用户信息的 DTO 类,例如:

@Data
public class UserDTO implements UserDetails {

    private Long id;

    private String username;

    private String password;

    private Boolean enabled;

    @Override
    public Collection getAuthorities() {
        return AuthorityUtils.NO_AUTHORITIES;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return enabled == null || enabled;
    }
}

然后,定义一个 Mapper 接口来访问 sys_user 表,例如:

@Mapper
public interface UserMapper extends BaseMapper {

    /**
     * 根据用户名获取用户信息
     *
     * @param username 用户名
     * @return 用户信息
     */
    UserDTO findByUsername(String username);
}

这里使用了 Mybatis Plus 的 BaseMapper 泛型接口来继承了基本的增、删、改、查操作,并且定义了一个新的方法来根据用户名获取用户信息。其中,@Mapper 注解表示该接口是一个 Mybatis Mapper 接口,由 Mybatis 解析并生成相应的实现类。

5.定义 Service

通过定义 DAO,我们现在已经能够使用 Mybatis Plus 来访问数据库,接下来需要定义 Service 层来对 DAO 层进行封装,提供给 Controller 层调用。例如,我们定义一个名为 UserServiceImpl 的 Service 实现类:

@Service
public class UserServiceImpl implements UserDetailsService {
    
    @Autowired
    private UserMapper userMapper;
    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserDTO user = userMapper.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("No matching user found for " + username);
        }
        return user;
    }
}

在代码中,我们通过 @Autowired 注解将 

UserMapper注入到UserServiceImpl中,并实现了UserDetailsService接口的loadUserByUsername()` 方法,根据用户名查询用户信息并返回给 Spring Security 使用。

6.配置 Spring Security

最后,需要配置 Spring Security,使用上述 Service 实现类来进行用户认证和授权。在 Spring Boot 的配置文件中添加如下配置:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
                .logout()
                .permitAll();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }
}

在上述代码中,我们定义了一个 WebSecurityConfig 配置类,并继承自 WebSecurityConfigurerAdapter,用于配置 Spring Security。在 configure(HttpSecurity) 方法中,我们定义了登录页面、授权规则和登录方式。在 configureGlobal(AuthenticationManagerBuilder) 方法中,我们将上述 Service 实现类注入到 AuthenticationManagerBuilder 中,使其能够在登录时调用该 Service 实现类进行认证操作。

现在,当用户在登录页面中输入用户名和密码时,Spring Security 就会自动调用上述 Service 实现类来进行用户认证。如果认证成功,用户就能够访问被授权的资源。如果认证失败,则会抛出相应的异常,例如 UsernameNotFoundExceptionBadCredentialsException 等。

以下是一个使用 Mybatis Plus、Spring Security 和 Controller 的实例:

1.定义 Controller

定义一个 UserController 类来作为 Spring Boot 的 Web 接口,例如:

@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/")
    public List findAll() {
        return userService.list();
    }

    @GetMapping("/{id}")
    public UserDTO findById(@PathVariable Long id) {
        return userService.getById(id);
    }

    @PostMapping("/")
    public UserDTO create(@RequestBody UserDTO user) {
        userService.save(user);
        return user;
    }

    @PutMapping("/{id}")
    public UserDTO update(@PathVariable Long id, @RequestBody UserDTO user) {
        user.setId(id);
        userService.updateById(user);
        return user;
    }

    @DeleteMapping("/{id}")
    public void delete(@PathVariable Long id) {
        userService.removeById(id);
    }
}

在上述代码中,我们使用 @RestController 注解来定义一个 RESTful 风格的控制器,使用 @RequestMapping 注解来指定请求的路径。在控制器类中,我们通过 @Autowired 注解将 Service 接口注入到 Controller 中,使用 @GetMapping@PostMapping@PutMapping 和 @DeleteMapping 注解来分别定义 GET、POST、PUT 和 DELETE 请求的处理方法。

2.添加 Swagger 文档支持

为了方便地查看和测试接口,我们可以使用 Swagger UI 来生成文档和测试接口。

首先,在 Maven 中添加 Swagger2 和 Swagger UI 的依赖:




    io.springfox
    springfox-swagger2
    2.10.5



    io.springfox
    springfox-swagger-ui
    2.10.5

然后,在 Spring Boot 的配置文件中添加如下配置:

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.example.demo.controller"))
                .paths(PathSelectors.any())
                .build();
    }
}

最后,启动 Spring Boot 应用,访问 http://localhost:8080/swagger-ui.html 即可看到 Swagger 文档和测试接口的界面。

现在,在 Swagger UI 中可以方便地测试 CRUD 操作接口,验证 Mybatis Plus 和 Spring Security 的整合效果。

2023/4/10 20:33:00

之前你不是在controller层加注解@PreAuthorize("hasAuthority('ROLE_ADMIN')")实现过滤的吗,为何这里不需要?

重试

复制

你提到的 @PreAuthorize("hasAuthority('ROLE_ADMIN')") 注解是用来控制方法的访问权限的,可以在 Controller 层的方法上添加该注解来进行权限控制,保证只有具有相应权限的用户才能访问该接口。

在我的之前的范例中,之所以需要添加该注解是因为我们控制了访问 /admin 路径的权限,只有具有 ROLE_ADMIN 角色的用户才能访问到该路径下的接口。而在这个示例中,我没有控制任何路径的权限,只是使用了 Spring Security 来实现用户的身份认证和访问授权。

在实际开发中,根据业务需求和安全性要求,可以在 Controller 层的每个方法上添加不同的权限控制注解,以实现更加细粒度的权限控制。

2023/4/10 20:39:29

现在在Controller层加上@PreAuthorize,我想看看如何控制

重试

复制

好的,我来给你举个例子:

假设我们的应用需要实现通过用户角色来控制访问权限,例如只有拥有 ADMIN 角色的用户才能访问某些接口,我们可以在 Controller 层的方法上使用 @PreAuthorize 注解来实现权限控制。

首先,我们需要在 pom.xml 文件中添加 Spring Security 的依赖:



    org.springframework.boot
    spring-boot-starter-security

然后,我们可以在 WebSecurityConfig 配置类中设置拦截规则,例如:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/**").hasRole("ADMIN") // 只有 ADMIN 角色可以访问 /admin 路径下的接口
                .anyRequest().authenticated()
                .and().formLogin()
                .and().httpBasic();
    }
}

在上述代码中,我们设置了只有拥有 ADMIN 角色的用户可以访问 /admin/** 路径下的接口,并且其他的请求都需要进行身份认证才能访问。

接着,我们可以在 Controller 层中使用 @PreAuthorize 注解来控制方法的访问权限,例如:

@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    @PreAuthorize("hasRole('ADMIN')") // 只有 ADMIN 角色可以访问该接口
    @GetMapping("/")
    public List findAll() {
        return userService.list();
    }

    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") // 只有 USER 或 ADMIN 角色可以访问该接口
    @GetMapping("/{id}")
    public UserDTO findById(@PathVariable Long id) {
        return userService.getById(id);
    }

    @PreAuthorize("hasRole('ADMIN')") // 只有 ADMIN 角色可以访问该接口
    @PostMapping("/")
    public UserDTO create(@RequestBody UserDTO user) {
        userService.save(user);
        return user;
    }

    @PreAuthorize("hasRole('ADMIN')") // 只有 ADMIN 角色可以访问该接口
    @PutMapping("/{id}")
    public UserDTO update(@PathVariable Long id, @RequestBody UserDTO user) {
        user.setId(id);
        userService.updateById(user);
        return user;
    }

    @PreAuthorize("hasRole('ADMIN')") // 只有 ADMIN 角色可以访问该接口
    @DeleteMapping("/{id}")
    public void delete(@PathVariable Long id) {
        userService.removeById(id);
    }
}

在上述代码中,我们给每个需要控制访问权限的方法上添加了 @PreAuthorize 注解,并给该注解传递了相应的角色信息,例如 @PreAuthorize("hasRole('ADMIN')") 表示只有 ADMIN 角色可以访问该接口,@PreAuthorize("hasRole('USER') or hasRole('ADMIN')") 表示只有 USER 或 ADMIN 角色可以访问该接口等。

现在,我们就可以根据业务需求和安全性要求,使用 @PreAuthorize 注解来实现细粒度的方法级别权限控制。

2023/4/10 20:41:39

那么这个USER和'ADMIN'的权限我去哪里给每个用户定义呢?是在java程序里还是在mysql表里?或者说是其他方式

重试

复制

可以说在 Java 程序和 MySQL 中都可以定义用户的角色和权限。

一般来说,在 MySQL 中创建用户和角色并给予相应的权限是很常见的做法。可以在 MySQL 中创建一个用户表和角色表,然后再创建一个关联表来记录用户和角色之间的对应关系。例如:

CREATE TABLE user (
  id BIGINT NOT NULL AUTO_INCREMENT,
  username VARCHAR(64) NOT NULL,
  password VARCHAR(256) NOT NULL,
  PRIMARY KEY (id)
);

CREATE TABLE role (
  id BIGINT NOT NULL AUTO_INCREMENT,
  name VARCHAR(64) NOT NULL,
  PRIMARY KEY (id)
);

CREATE TABLE user_role (
  user_id BIGINT NOT NULL,
  role_id BIGINT NOT NULL,
  PRIMARY KEY (user_id, role_id),
  FOREIGN KEY (user_id) REFERENCES user (id),
  FOREIGN KEY (role_id) REFERENCES role (id)
);

然后,在 Java 程序中,可以通过 UserRepository 和 RoleRepository 来操作用户和角色等相关信息,例如:

public interface UserRepository extends JpaRepository {
    User findByUsername(String username);
}

public interface RoleRepository extends JpaRepository {
    Role findByName(String name);
}

只要有了这些信息,就可以在 Spring Security 的配置类中将用户和角色关联起来,并授权给相应的角色。

例如,在上面提到的 WebSecurityConfig 配置类中,可以使用 UserDetailsService 来获取用户相关信息,并将用户和角色在内存中进行对应和授权:

@Autowired
private UserRepository userRepository;

@Autowired
private RoleRepository roleRepository;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(username -> {
        User user = userRepository.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("User " + username + " not found");
        }
        Set authorities = new HashSet<>();
        for (Role role : user.getRoles()) {
            authorities.add(new SimpleGrantedAuthority(role.getName()));
        }
        return new org.springframework.security.core.userdetails.User(
                user.getUsername(), user.getPassword(), authorities);
    });
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .antMatchers("/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
            .and().formLogin()
            .and().httpBasic();
}

在上述代码中,我们使用 UserDetailsService 对象来获取用户相关信息,并将用户和角色在内存中进行对应和授权,这样用户就可以根据自己的角色来访问相应的接口了。

当然,这只是一个比较简单的示例,真实的应用场景可能会更加复杂,需要根据实际情况来灵活地设计用户和角色的关系,并进行相应的授权。

你可能感兴趣的:(mybatis,spring,boot,java)