引入

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

应用安全

  • 防止攻击

    • DDos、CSRF、XSS、SQL注入...

  • 控制权限

    • 登录的用户能干什么

    • 用户登录系统以后要控制住用户的所有行为,防止越权

  • 传输加密

    • https

    • X509

  • 认证

    • OAuth2.0

    • JWT


RBAC权限模型

Role Based Access Controll:基于角色的访问控制

一个网站可以有许多用户,每个用户可以有许多角色,每个角色可以关联许多权限

  • 认证:用户登录

  • 授权:给每个方法规定好权限,由权限框架否则判断调用者是否有指定权限


认证

配置类

package com.tlovo.security.config;
​
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.security.reactive.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.web.server.SecurityWebFilterChain;
​
@Configuration
@EnableWebFluxSecurity
@RequiredArgsConstructor
public class SecurityAppConfiguration {
​
    private final ReactiveUserDetailsService userDetailsService;
​
    @Bean
    SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        // 1.定义哪些请求需要认证,哪些不需要
        http.authorizeExchange(auth -> {
            // 允许所有人访问匹配请求路径
            // auth.pathMatchers("/**").permitAll();
​
            // 允许访问所有静态资源
            auth.matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll();
​
            // 剩下的都需要认证
            auth.anyExchange().authenticated();
        });
​
        // 2.开启默认表单登录
        http.formLogin();
​
        // 3.安全控制
        http.csrf(csrfSpec -> {
            csrfSpec.disable();
        });
​
        // 4.配置 认证规则(数据库查询)
        http.authenticationManager(new UserDetailsRepositoryReactiveAuthenticationManager(userDetailsService));
​
        // 构建安全配置
        return http.build();
    }
}

用户信息服务

package com.tlovo.security.component;
​
import lombok.RequiredArgsConstructor;
import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
​
@Component
@RequiredArgsConstructor
public class UserDetailsService implements ReactiveUserDetailsService {
​
    private final DatabaseClient databaseClient;
​
    // 自定义如何按照用户名去数据库查询用户信息
    @Override
    public Mono<UserDetails> findByUsername(String username) {
        return databaseClient.sql("select u.*,r.id rid,r.name,r.value,pm.id pid,pm.value pvalue,pm.description"
                        + " from t_user u"
                        + " left join t_user_role ur on ur.user_id=u.id"
                        + " left join t_roles r on r.id=ur.role_id"
                        + " left join t_role_perm rp on rp.role_id=r.id"
                        + " left join t_perm pm on rp.perm_id=pm.id"
                        + " where u.username=? limit 1")
                .bind(0, username)
                .fetch()
                .one() // all
                .map(map -> {
                    return User.builder()
                            .username(username)
                            .password(map.get("password").toString())
                            .authorities("download", "delete", "view") // 权限 - 应该从数据库获取
                            .roles("admin", "sale") // 身份 - 应该从数据库获取
                            .build();
                });
    }
}

规则,就是用来打破的( ̄へ ̄)!