Spring Security

发布时间:2024年01月21日

目标:
SpringBoot3+Webflux+ Spring Data R2dbc + Spring Security

配置认证规则

导入相关依赖

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <r2dbc-mysql.version>1.0.5</r2dbc-mysql.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>io.asyncer</groupId>
            <artifactId>r2dbc-mysql</artifactId>
            <version>${r2dbc-mysql.version}</version>
        </dependency>

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

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

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-r2dbc</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
    </dependencies>
应用安全

防止攻击:
DDos,CSRF,XSSSQL注入
控制权限:
登录用户能干什么
用户登录系统以后要控制用户所有的行为,防止越权
传输加密:
https
X509
认证:
OAuth2.0
JWT

RBAC权限模型

Role Based Access Control:基于角色的访问控制
一个网站有很多用户
每个用户可以有很多角色
一个角色可以关联很多权限
一个人能干什么?(权限控制)
找到这个人,看他有哪些角色,每个角色拥有哪些权限
这个人就拥有一堆的角色或者权限
这个人在执行方法时,给方法规定好权限
由权限框架负责判断这个人是否有指定的权限
所有权限框架:
1.让用户登录进来(认证:各种方式让用户进来)
2.查询用户拥有的所有角色和权限(授权:每个方法执行的时候,匹配角色或者权限来判定用户是否可以执行这个方法)

导入spring security默认行为:所有请求都需要登录才能访问
1.SecurityAutoConfiguration:
导入SecurityFilterChain组件:默认所有请求都需要登录(之前)
2.SecurityFilterAutoConfiguration
3.ReactiveSecurityAutoConfiguration:
导入ServerHttpSecurityConfiguration配置:
注解导入ServerHttpSecurityConfiguration
4.MethodSecurityAspectJAutoProxyRegistrar

controller

@RestController
@RequestMapping
public class HelloController {

    @GetMapping("/sayHello")
    public Mono<String> sayHello() {
        return  Mono.just("hello,world!");
    }
}

默认效果:
在这里插入图片描述

认证

登录行为:
1.静态资源放行
2.其他请求需要登录

@Configuration
public class SecurityConfiguration {

    @Bean
    public SecurityWebFilterChain securityFilterChain(ServerHttpSecurity http) {
        //1.定义哪些请求需要认证,哪些请求不需要
        http.authorizeExchange(authorize -> {
            //1.1.允许所有人访问静态资源
            authorize.matchers(PathRequest.toStaticResources().atCommonLocations())
                    .permitAll();
            //1.2.剩下的所有请求都需要认证(登录)
            authorize.anyExchange().authenticated();
        });
        //2.开启默认的表单登录
        http.formLogin();

        //3.安全控制
        http.csrf(ServerHttpSecurity.CsrfSpec::disable);
        //构建出安全配置
        return http.build();
    }
}

认证逻辑自定义UserDetails数据

目前认证:
用户名user,密码是默认生成的
期望:去数据库查
在这里插入图片描述
这个界面点击登录,最终spring security框架会按照ReactiveUserDetailservice组件,
按照表单提交的用户名,去数据库查询用户详情
基本信息:账号密码,角色,权限
把数据库中返回的用户详情中密码和表单提交的密码进行比较
比较成功则登录成功
原始sql

SELECT user.username,user.password,user_role.role_id,roles.name,perm.uri
FROM index_demo.t_user user
LEFT JOIN t_user_role user_role ON user.id = user_role.user_id
LEFT JOIN index_demo.t_roles roles ON user_role.role_id = roles.id
LEFT JOIN index_demo.t_role_perm role_perm ON role_perm.role_id = roles.id
LEFT JOIN index_demo.t_perm perm ON role_perm.perm_id = perm.id
WHERE user.username = 'zyl';

配置认证规则:如何去数据库中查询用户
配置默认密码加密器

@Configuration
public class SecurityConfiguration {

    @Autowired
    private ReactiveUserDetailsService reactiveUserDetailsService;

    @Bean
    public SecurityWebFilterChain securityFilterChain(ServerHttpSecurity http) {
        //1.定义哪些请求需要认证,哪些请求不需要
        http.authorizeExchange(authorize -> {
            //1.1.允许所有人访问静态资源
            authorize.matchers(PathRequest.toStaticResources().atCommonLocations())
                    .permitAll();
            //1.2.剩下的所有请求都需要认证(登录)
            authorize.anyExchange().authenticated();
        });
        //2.开启默认的表单登录
        http.formLogin();

        //3.安全控制
        http.csrf(ServerHttpSecurity.CsrfSpec::disable);

        //4.配置认证规则:如何去数据库中查询用户
        //
        http.authenticationManager(
                new UserDetailsRepositoryReactiveAuthenticationManager(reactiveUserDetailsService)
        );
        //构建出安全配置
        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder () {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }
}

自定义登录校验

@Service
public class MyReactiveUserDetailService implements ReactiveUserDetailsService {

    @Autowired
    private DatabaseClient databaseClient;

    /**
     * 自定义如何按照用户名去数据库查用户信息
     */
    @Override
    public Mono<UserDetails> findByUsername(String username) {
        return databaseClient.sql("SELECT user.username,user.password,user_role.role_id,roles.name,perm.uri " +
                "FROM index_demo.t_user user " +
                "LEFT JOIN index_demo.t_user_role user_role ON user.id = user_role.user_id " +
                "LEFT JOIN index_demo.t_roles roles ON user_role.role_id = roles.id " +
                "LEFT JOIN index_demo.t_role_perm role_perm ON role_perm.role_id = roles.id " +
                "LEFT JOIN index_demo.t_perm perm ON role_perm.perm_id = perm.id " +
                "WHERE user.username = ?")
                .bind(0,username)
                .fetch()
                .first()
                .map(rowMap ->
                     User.builder()
                            .username(String.valueOf(rowMap.get("username")))
                            .password(String.valueOf(rowMap.get("password")))
                            .authorities(String.valueOf(rowMap.get("uri")))//权限
                            .roles(String.valueOf(rowMap.get("name")))
                            .build()
                );
    }
}

方法级别鉴权

角色和权限都被封装成SimpleGrantedauthority

@RestController
@RequestMapping
public class HelloController {

    @PreAuthorize("hasRole('admin')")
    @GetMapping("/hello")
    public Mono<String> sayHello() {
        return  Mono.just("hello,world!");
    }

    @PreAuthorize("hasAuthority('list')")
    @GetMapping("/word")
    public Mono<String> word() {
        return Mono.just("word!");
    }
}

对应权限:
在这里插入图片描述

文章来源:https://blog.csdn.net/bennettzhou404/article/details/135712975
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。