赞
踩
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 的依赖:
- <!-- pom.xml -->
-
- <dependency>
- <groupId>com.baomidou</groupId>
- <artifactId>mybatis-plus-boot-starter</artifactId>
- <version>3.4.2</version>
- </dependency>
-
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-security</artifactId>
- <version>2.5.2</version>
- </dependency>
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<? extends GrantedAuthority> 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<UserDTO> {
-
- /**
- * 根据用户名获取用户信息
- *
- * @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 实现类来进行用户认证。如果认证成功,用户就能够访问被授权的资源。如果认证失败,则会抛出相应的异常,例如 UsernameNotFoundException
、BadCredentialsException
等。
以下是一个使用 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<UserDTO> 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 的依赖:
- <!-- pom.xml -->
-
- <dependency>
- <groupId>io.springfox</groupId>
- <artifactId>springfox-swagger2</artifactId>
- <version>2.10.5</version>
- </dependency>
-
- <dependency>
- <groupId>io.springfox</groupId>
- <artifactId>springfox-swagger-ui</artifactId>
- <version>2.10.5</version>
- </dependency>
然后,在 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 的依赖:
- <!-- pom.xml -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-security</artifactId>
- </dependency>
然后,我们可以在 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<UserDTO> 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, Long> {
- User findByUsername(String username);
- }
-
- public interface RoleRepository extends JpaRepository<Role, Long> {
- 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<GrantedAuthority> 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
对象来获取用户相关信息,并将用户和角色在内存中进行对应和授权,这样用户就可以根据自己的角色来访问相应的接口了。
当然,这只是一个比较简单的示例,真实的应用场景可能会更加复杂,需要根据实际情况来灵活地设计用户和角色的关系,并进行相应的授权。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。