本文最后更新于:2022年5月20日 下午
摘要:Spring Security web权限认证的三种方案。针对自定义编写实现类方式,详细介绍了使用Mybatis-Plus访问数据库完成用户认证。
Spring Security web权限方案
Spring Security中的web权限方案分为认证和授权。
设置登录的用户名和密码
- 通过配置文件
- 通过配置类
- 自定义编写实现类
配置文件方式
在【application.properties】中设置
1 2
| spring.security.user.name=root spring.security.user.password=root
|
配置类方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package com.shg.securitydemo.config;
import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); String password = passwordEncoder.encode("root"); auth.inMemoryAuthentication() .passwordEncoder(passwordEncoder) .withUser("root") .password(password) .roles("admin"); } }
|
自定义编写实现类方式
自定义实现类设置
- 创建配置类,设置使用哪个UserDetailService实现类
- 编写实现类,返回User对象,User对象有用户名密码和操作权限
自定义方式开发步骤
- 创建配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package com.shg.securitydemo.config;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration public class SecurityConfig1 extends WebSecurityConfigurerAdapter {
@Autowired private UserDetailsService userDetailsService;
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); auth.userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder); } }
|
- 编写【UserDetailsService】的实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package com.shg.securitydemo.service;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service;
import java.util.List;
@Service(value = "userDetailsService") public class MyUserDetailsService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("role"); return new User("root", new BCryptPasswordEncoder().encode("root"), authorities); } }
|
查询数据库完成用户认证
整合Mybatis-Plus完成数据库操作
- 引入相关依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.1</version> </dependency>
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
|
- 创建数据库和数据库表
创建一个user表结构如下,包含id、name、password三个字段
- 创建user表对应实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package com.shg.securitydemo.entity;
import lombok.Data;
@Data public class User { private int id; private String name; private String password; }
|
- 整合Mybaist-Plus,创建接口【UserMapper】,继承【BaseMapper】
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package com.shg.securitydemo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.shg.securitydemo.entity.User; import org.apache.ibatis.annotations.Mapper;
@Mapper public interface UserMapper extends BaseMapper<User> { }
|
- 在【UserDetailsService】实现类中查询数据库进行认证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| package com.shg.securitydemo.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.shg.securitydemo.entity.User; import com.shg.securitydemo.mapper.UserMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service;
import java.util.List;
@Service(value = "userDetailsService1") public class MyUserDetailsService1 implements UserDetailsService {
@Autowired private UserMapper userMapper;
@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("name", username); User user = userMapper.selectOne(wrapper); if (user == null) { throw new UsernameNotFoundException("用户名不存在!"); } List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
return new org.springframework.security.core.userdetails.User(user.getName(), new BCryptPasswordEncoder().encode(user.getPassword()), authorities); } }
|
- 创建配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package com.shg.securitydemo.config;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration public class SecurityConfig2 extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService;
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); auth.userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder); } }
|
- 在启动类【SecurityDemoApplication】中加入@MapperScan注解指定扫描包
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package com.shg.securitydemo;
import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication @MapperScan(value = {"com.shg.securitydemo.mapper"}) public class SecurityDemoApplication { public static void main(String[] args) { SpringApplication.run(SecurityDemoApplication.class, args); } }
|
- 在【application.properties】中配置数据库连接
1 2 3 4 5
| spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/security?serverTimezone=GMT%2B8 spring.datasource.username=root spring.datasource.password=root
|
自定义登录页面
- 在配置类中重写configure(HttpSecurity http)方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| package com.shg.securitydemo.config;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration public class SecurityConfig2 extends WebSecurityConfigurerAdapter {
@Autowired private UserDetailsService userDetailsService;
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); auth.userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder); }
@Override protected void configure(HttpSecurity http) throws Exception { http.formLogin() .loginPage("/login.html") .loginProcessingUrl("/user/login") .defaultSuccessUrl("/test/index").permitAll() .and().authorizeRequests() .antMatchers("/", "/test/hello", "/user/login").permitAll() .anyRequest().authenticated() .and().csrf().disable(); } }
|
- 编写一个login.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>login</title> </head> <body> <form action="/user/login" method="post"> 用户名:<input type="text" name="username"> <br /> 密码:<input type="text" name="password"> <br /> <input type="submit" value="login"> </form> </body> </html>
|
- 在【TestController】中定义一个访问首页的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package com.shg.securitydemo.controller;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;
@RestController @RequestMapping("/test") public class TestController {
@GetMapping("hello") public String hello() { return "hello security"; }
@GetMapping("/index") public String index() { return "index"; }
}
|