Spring Security

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

配置认证规则

导入相关依赖

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

    <dependencies>
        <dependency>
            <groupId>io.asyncergroupId>
            <artifactId>r2dbc-mysqlartifactId>
            <version>${r2dbc-mysql.version}version>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webfluxartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.datagroupId>
            <artifactId>spring-data-r2dbcartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-securityartifactId>
        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!");
    }
}

默认效果:
Spring Security_第1张图片

认证

登录行为:
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_第2张图片
这个界面点击登录,最终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!");
    }
}

对应权限:
Spring Security_第3张图片

你可能感兴趣的:(spring,java,后端)