SpringSecurity基本使用

1.基本使用

1.pom依赖

 		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

2.编写Controller测试

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello World!";
    }
}

3.启动项目,访问 http://localhost:9999/hello

在这里插入图片描述

用户名为 user,密码在启动项目的控制台可以看到:

在这里插入图片描述

输入后显示文字:
在这里插入图片描述

2.自定义配置用户名与密码

方式一:在配置文件里配置

spring.security.user.name=admin
spring.security.user.password=123456
spring.security.user.roles=admin

方式二:配置类里配置

@Configuration
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String password = passwordEncoder.encode("123456");
        auth.inMemoryAuthentication().withUser("admin").password(password).roles("admin");
    }

    @Bean
    PasswordEncoder password() {
        return new BCryptPasswordEncoder();
    }
}

方式三:动态地从数据库中查

1.建表

CREATE TABLE `db_user`(
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(20) NOT NULL,
  `password` varchar(255) NULL,
  PRIMARY KEY (`id`)
);

2.pom

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1.tmp</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>

3.配置数据源

spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/db_user?useSSL=false&serverTimezone=Asia/Shanghai

4.编写实体类

@Data
@TableName("tb_user")
public class LoginUser {
    private Integer id;
    private String username;
    private String password;
}

5.Mapper

@Mapper
public interface UserMapper extends BaseMapper<LoginUser> {
}

6.编写Service

@Service("userDetailsService")
public class UserDeatilsServiceImpl implements UserDetailsService {

    @Resource
    UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
       //1.构建查询条件,从数据库查询用户
        QueryWrapper<LoginUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",s);
        LoginUser loginUser = userMapper.selectOne(queryWrapper);
        //2.将用户信息转换为springsecurity中的User
        List<GrantedAuthority> authority = AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_admin,ROLE_sale");
        User user = new User(loginUser.getUsername(),
                new BCryptPasswordEncoder().encode(loginUser.getPassword()),
                authority);
        return user;
    }
}

7.将Service注册到SpringSecurity中

@Configuration
public class MyWebSecurityConfig02 extends WebSecurityConfigurerAdapter {

    @Autowired
    UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    @Bean
    PasswordEncoder password() {
        return new BCryptPasswordEncoder();
    }
}

3.自定义登录页面

@Configuration
public class MyWebSecurityConfig02 extends WebSecurityConfigurerAdapter {

    @Autowired
    UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    @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()
                .and().authorizeRequests()
                    .anyRequest().authenticated()
                .and().csrf().disable();
    }

    @Bean
    PasswordEncoder password() {
        return new BCryptPasswordEncoder();
    }
}

/static/login.html:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title>登录</title>
</head>
<body>
<form action="/user/login" method="post">
    用户名:<input type="text" name="username"/><br/>
    密码:<input type="password" name="password"/><br/>
    <input type="submit" value="提交"/>
</form>
</body>
</html>

4.基于权限访问控制

SpringSecurity判断时是从UserDetailsService中获取用户,进而判断用户是否满足角色或者权限。

@Service("userDetailsService")
public class UserDeatilsServiceImpl implements UserDetailsService {

    @Resource
    UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        //1.构建查询条件,从数据库查询用户
        QueryWrapper<LoginUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",s);
        LoginUser loginUser = userMapper.selectOne(queryWrapper);
        //2.将用户信息转换为springsecurity中的User
        List<GrantedAuthority> authority = AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_admin,ROLE_sale");
        User user = new User(loginUser.getUsername(),
                new BCryptPasswordEncoder().encode(loginUser.getPassword()),
                authority);
        return user;
    }
}

1.在配置类里配置

   @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                .loginPage("/login.html")
                .loginProcessingUrl("/user/login")
                .defaultSuccessUrl("/test/index").permitAll()
                .and().authorizeRequests()
                    .antMatchers("/","/user/login").permitAll()
                .and().authorizeRequests()
                    .antMatchers("/test/hello","/admin2")
                        .hasAnyRole("sale,admin")
                .and().authorizeRequests()
                    .anyRequest().authenticated()
                .and().csrf().disable();
    }

(1)hasAuthority方法:

.antMatchers("/admin","/admin2").hasAuthority("admin")

(2)hasAnyAuthority方法:满足其中一个就放行,多个权限用逗号隔开

.antMatchers("/admin","/admin2").hasAnyAuthority("admin,teacher")
.antMatchers("/admin","/admin2").hasAnyAuthority("admin","teacher")

(3)hasRole方法:

*注意:UserDetailsService中返回的用户里的角色是带ROLE_前缀的,但在配置里不需要写前缀。因为hasRole方法最终会帮我们加入前缀。

在这里插入图片描述

.hasRole("admin")

hasAnyRole:使用方法同hasAnyAuthority

.hasAnyRole("sale,admin")

5.自定义403

当权限验证没通过的时候就会报403,但是默认返回的页面我们不是很满意,就可以在配置类里自定义去进行更改。

	 @Override
    protected void configure(HttpSecurity http) throws Exception {
		http.exceptionHandling().accessDeniedPage("/unauth");
    }

其中/auth可以自己定义,可以写为一个url,这样403的时候就会跳转到对应url的Controller的方法里:

	@RequestMapping("/unauth")
    public String unauth() {
        return "权限不足,请联系管理员";
    }

也可以写网页的路径,如/403.html,然后在 resource/static文件夹下创建网页。

6.使用注解

@Secured、@PreAuthorize、@PostAuthorize

1.首先在启动类上开启

想启用哪个注解就开哪个:

在这里插入图片描述

@SpringBootApplication
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityApplication {

    public static void main(String[] args) {
        SpringApplication.run(SecurityApplication.class, args);
    }

}

2.在方法上标注解

  • @Secured 判断是否具有角色,另外需要注意的是这里匹配的字符串需要添加前缀“ROLE_“。

    @ResponseBody
    @Secured({"ROLE_normal","ROLE_admin"})
    public String helloUser() {
    	return "hello,user";
    }
    
  • @PreAuthorize:注解适合进入方法前的权限验证, @PreAuthorize 可以将登录用户的 roles/permissions 参数传到方法中。

    @RequestMapping("/preAuthorize")
    @ResponseBody
    //@PreAuthorize("hasRole('ROLE_管理员')")
    @PreAuthorize("hasAnyAuthority('menu:system')")
    public String preAuthorize(){
    	System.out.println("preAuthorize");
    	return "preAuthorize";
    }
    
    /**
     * 限制只能查询自己的信息
     */
    @PreAuthorize("principal.username.equals(#username)")
    public User find(String username) {
        return null;
    }
    

    权限表达式:https://docs.spring.io/spring-security/site/docs/5.3.4.RELEASE/reference/html5/#overview-2

  • @PostAuthorize @PostAuthorize 注解使用并不多,在方法执行后再进行权限验证,适合验证带有返回值的权限.

    @RequestMapping("/testPostAuthorize")
    @ResponseBody
    @PostAuthorize("hasAnyAuthority('menu:system')")
    public String preAuthorize(){
    	System.out.println("test--PostAuthorize");
    	return "PostAuthorize"; 
    }
    
@PostFilter、@PreFilter

@PostFilter : 权限验证之后对数据进行过滤 留下用户名是 admin1 的数据

表达式中的 filterObject 引用的是方法返回值 List 中的某一个元素

@RequestMapping("getAll")
@PreAuthorize("hasRole('ROLE_管理员')")
@PostFilter("filterObject.username == 'admin1'")
@ResponseBody
public List<UserInfo> getAllUser(){
 	ArrayList<UserInfo> list = new ArrayList<>();
    list.add(new UserInfo(1l,"admin1","6666"));
 	list.add(new UserInfo(2l,"admin2","888"));
	return list;
}

3.7.5 @PreFilter

@PreFilter: 进入控制器之前对数据进行过滤

@RequestMapping("getTestPreFilter")
@PreAuthorize("hasRole('ROLE_管理员')")
@PreFilter(value = "filterObject.id%2==0")
@ResponseBody
public List<UserInfo> getTestPreFilter(@RequestBody List<UserInfo> list){
    list.forEach(t-> {
        System.out.println(t.getId()+"\t"+t.getUsername());
    });
	return list;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值