Skip to content

认证与授权机制

认证和授权不能混着看。认证决定 Authentication 怎么产生,授权决定这个对象有没有访问资格。

认证核心类

  • Authentication
  • AuthenticationManager
  • AuthenticationProvider
  • UserDetailsService
  • UserDetails
  • PasswordEncoder
  • SecurityContextHolder
java
@Bean
PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

表单登录链路

java
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
            .formLogin(form -> form.loginPage("/login").permitAll())
            .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
            .build();
}

运行时链路:

  1. UsernamePasswordAuthenticationFilter 读取用户名密码。
  2. 组装未认证 UsernamePasswordAuthenticationToken
  3. 交给 AuthenticationManager
  4. DaoAuthenticationProvider 查询用户、校验密码。
  5. 成功后写入 SecurityContextHolder

自定义登录接口

java
@RestController
@RequestMapping("/auth")
class AuthController {

    private final AuthenticationManager authenticationManager;

    AuthController(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @PostMapping("/login")
    Map<String, Object> login(@RequestBody LoginRequest request) {
        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(request.username(), request.password()));
        SecurityContextHolder.getContext().setAuthentication(authentication);
        return Map.of("username", authentication.getName());
    }
}
java
public record LoginRequest(String username, String password) {}

基于 URL 的授权

java
@Bean
SecurityFilterChain apiChain(HttpSecurity http) throws Exception {
    return http
            .authorizeHttpRequests(auth -> auth
                    .requestMatchers("/api/admin/**").hasRole("ADMIN")
                    .requestMatchers("/api/orders/**").hasAnyAuthority("order:read", "order:write")
                    .anyRequest().authenticated())
            .build();
}

方法级授权

java
@Configuration
@EnableMethodSecurity
class MethodSecurityConfig {
}
java
@Service
class OrderService {

    @PreAuthorize("hasRole('ADMIN')")
    public void deleteOrder(Long orderId) {
    }

    @PreAuthorize("hasAuthority('order:read')")
    public String queryOrder(Long orderId) {
        return "ok";
    }
}

角色与权限建模

  • ROLE_ADMIN:粗粒度角色。
  • order:read:资源权限。
  • 企业项目通常两者并存,角色映射岗位,权限映射动作。