如何为 RestController 配置 SpringBoot 认证

Posted

技术标签:

【中文标题】如何为 RestController 配置 SpringBoot 认证【英文标题】:How to configure SpringBoot authentication for RestController 【发布时间】:2021-12-09 08:33:23 【问题描述】:

我有一个用户控制器包含

@PostMapping("/user/register")
public String register  ( @RequestParam String name
                        , @RequestParam String password
                        , @RequestParam String email
                        , HttpServletRequest request)

@GetMapping("/user/confirm/token")
public Optional<User> confirm(@PathVariable(value = "token") String token)

    @PostMapping("/user/login")
public ResponseEntity<String> login 
                            ( @RequestParam String email
                            , @RequestParam String password
                            , HttpServletRequest request
                            )
    //System.out.println("post:/user/login email="+email);
    User user = userService.login(email, password);
    if (user==null)
        return ResponseEntity.notFound().build();
    
    HttpSession session = request.getSession(true); // createSession=true
    session.setAttribute(SESSION_USER, user);
    
    **cfgSecurity.setAthenticated(session, user);**
    
    return ResponseEntity.ok("OK");

用户的角色是一个枚举。 问题是如何配置安全性。 这是我的配置类:

@Configuration
@EnableWebSecurity
public class CfgSecurity extends WebSecurityConfigurerAdapter

    private static final String PRINCIPAL  = "admin";
    private static final String CREDENTIAL = "password";
    @Autowired AuthenticationManager authenticationManager;
    
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception  // authentication
        auth
          .inMemoryAuthentication()
          .withUser(PRINCIPAL).password(passwordEncoder().encode(CREDENTIAL))
          .roles(roles());
    

    @Override
    protected void configure(HttpSecurity http) throws Exception  // resource security
        http.cors().and().csrf().disable()
            .httpBasic()
            /*
            .and().authorizeRequests()
                .antMatchers("/user/register").permitAll()//.hasRole("ADMIN")
                .antMatchers("/user/confirm/**").permitAll()
                .anyRequest().permitAll()
                
            //.and().formLogin().loginPage("/user/login").permitAll()
             */
          ;
    
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception
    
        //https://www.programcreek.com/java-api-examples/docs/?api=org.springframework.security.authentication.AuthenticationManager
        return super.authenticationManagerBean();
    
    
    @Bean
    public PasswordEncoder passwordEncoder() 
        return new BCryptPasswordEncoder();
    
    

    @Bean
    CorsConfigurationSource corsConfigurationSource() 
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("*"));
        configuration.setAllowedHeaders(Arrays.asList("*"));
        configuration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    
    private static String[] roles() 
        String[] array = new String[Role.values().length];
        for (Role role : Role.values()) 
            array[role.ordinal()] = role.name();
        
        return array;
    

    public void setAthenticated(HttpSession session, User user) 
        //https://***.com/questions/4664893/how-to-manually-set-an-authenticated-user-in-spring-security-springmvc
        try 
            Authentication authRequest = new UsernamePasswordAuthenticationToken
                        (PRINCIPAL, passwordEncoder().encode(CREDENTIAL)
                        , user.getAuthorities()
                        );
            Authentication authentication = authenticationManager.authenticate(authRequest);
            
            SecurityContext securityContext = SecurityContextHolder.getContext();
            securityContext.setAuthentication(authentication);
            session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext);
        
        catch(Exception ex) 
            System.err.println(ex.toString());
        
    

它不起作用:我明白了 org.springframework.security.authentication.BadCredentialsException:错误的凭据。

这里是 User.getAuthorities(在 setAuthenticated 中引用):

@覆盖 公共收藏 getAuthorities()

final SimpleGrantedAuthority simpleGrantedAuthority = 
        new SimpleGrantedAuthority(role.toString());
return Collections.singletonList(simpleGrantedAuthority);

【问题讨论】:

【参考方案1】:

这是它的工作方式:使用 AuthenticationManagerBuilder 的加密密码,但将其未加密传递给 UsernamePasswordAuthenticationToken。

public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception  
    auth.inMemoryAuthentication()
        .withUser(PRINCIPAL).password(passwordEncoder().encode(CREDENTIAL))
        .roles(roles());


public void setAthenticated(HttpSession session, User user) 
    Authentication authRequest = new UsernamePasswordAuthenticationToken
                        (PRINCIPAL, CREDENTIAL, user.getAuthorities());
    Authentication authentication = authenticationManager
                                      .authenticate(authRequest);
            
    SecurityContext securityContext = SecurityContextHolder.getContext();
    securityContext.setAuthentication(authentication);
    session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext);

【讨论】:

以上是关于如何为 RestController 配置 SpringBoot 认证的主要内容,如果未能解决你的问题,请参考以下文章

如何为生产者设置路由键

当我们有一个身份验证系统时,如何为某些链接添加基本身份验证

我应该如何为精灵表中的精灵分配名称?

WCF - 如何为 NTLM 身份验证配置 netTcpBinding?

如何为 EmrCreateJobFlowOperator 指定配置文件?

如何为 webmail 配置 SMTP