具有多种身份验证方法的 Web 安全设置

Posted

技术标签:

【中文标题】具有多种身份验证方法的 Web 安全设置【英文标题】:Web security setup with multiple authentication methods 【发布时间】:2021-12-13 00:53:59 【问题描述】:

我正在构建一个用户身份验证微服务,用于使用 Spring Boot 进行学习。我已经分别开发了 3 种不同的用户身份验证方法作为 3 个不同的项目(一种使用 PostgreSQL 数据库和 JWT 身份验证,另一种使用 OAuth2,另一种使用 LDAP)。现在我需要将这三个组合为一个服务。我已经设置了一些步骤。

目前我有以下内容:

这是我的SecurityConfigure.java 文件:

package com.persistent.userauthentication.security;

import com.persistent.userauthentication.filters.JwtRequestFilter;
import com.persistent.userauthentication.service.AuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfigure extends WebSecurityConfigurerAdapter 

    @Configuration
    @Order(1)
    public static class JwtWebSecurityConfig extends WebSecurityConfigurerAdapter
        @Autowired
        private AuthService authService;

        @Autowired
        private JwtRequestFilter jwtRequestFilter;

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception 
            auth.userDetailsService(authService);
        

        @Override
        protected void configure(HttpSecurity http) throws Exception 
            http
                .csrf().disable()
                .requestMatchers()
                    .antMatchers("/jwt/**")
                    .and()
                .authorizeRequests()
                    .antMatchers("/jwt/authenticate").permitAll()
                    .anyRequest().authenticated()
                    .and()
                .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS); //since we don't want to manage sessions

            http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
        

        @Override
        @Bean
        public AuthenticationManager authenticationManagerBean() throws Exception 
            return super.authenticationManagerBean();
        

        @Bean
        public PasswordEncoder passwordEncoder()
            return NoOpPasswordEncoder.getInstance();
        
    

    @Configuration
    @Order(2)
    public static class LdapSecurityConfig extends WebSecurityConfigurerAdapter
        @Override
        protected void configure(HttpSecurity http) throws Exception 
            http
                .antMatcher("/ldapauth/**")
                .authorizeRequests()
                    .anyRequest().fullyAuthenticated()
                    .and()
                .formLogin();
        

        @Override
        public void configure(AuthenticationManagerBuilder auth) throws Exception 
            auth
                .ldapAuthentication()
                    .userDnPatterns("uid=0,ou=people")
                    .groupSearchBase("ou=groups")
                    .contextSource()
                    .url("ldap://localhost:8389/dc=springframework,dc=org")
                    .and()
                .passwordCompare()
                    .passwordEncoder(new BCryptPasswordEncoder())
                    .passwordAttribute("userPassword");
        
    

    @Configuration
    @Order(3)
    public static class Oauth2SecurityConfig extends WebSecurityConfigurerAdapter

        @Override
        protected void configure(HttpSecurity http) throws Exception 
            http
                .antMatcher("/googleauth/**")
                .authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                .oauth2Login();
        
    

这是我的AuthController.java(控制器)文件:

package com.persistent.userauthentication.controller;

import com.persistent.userauthentication.model.AuthenticationRequest;
import com.persistent.userauthentication.model.AuthenticationResponse;
import com.persistent.userauthentication.service.AuthService;
import com.persistent.userauthentication.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;

@RestController
public class AuthController 
    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private AuthService authService;

    @Autowired
    private JwtUtil jwtTokenUtil;

    @RequestMapping(value = "/jwt/hello", method = RequestMethod.GET)
    public String Hello()
        return "basic auhentication successfull";
    

    @GetMapping("/googleauth/hello")
    public String GooglAauth()
        return "google authentication successful!";
    

    @RequestMapping(value = "/ldapauth/hello", method = RequestMethod.GET)
    public String LdapAuth()
        return "ldap authentication successful!";
    

    @RequestMapping(value = "/jwt/authenticate", method = RequestMethod.POST)
    public ResponseEntity<?> createAuthenticationToken(@RequestBody AuthenticationRequest authenticationRequest) throws Exception 

        try 
            authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), authenticationRequest.getPassword())
            );
         catch (BadCredentialsException e)
            throw new Exception("username or password is incorrect!", e);
        

        final UserDetails userDetails = authService.loadUserByUsername(authenticationRequest.getUsername());

        final String jwt = jwtTokenUtil.generateToken(userDetails);

        return ResponseEntity.ok(new AuthenticationResponse(jwt));
    

    @RequestMapping(value = "/jwt/extendtoken", method = RequestMethod.POST)
    public ResponseEntity<?> createNewAuthenticationToken(@RequestHeader("Authorization") String token) throws Exception 

        final String jwt = jwtTokenUtil.refreshToken(token);

        return ResponseEntity.ok(new AuthenticationResponse(jwt));
    

目前/jwt/hello(带有Authorization 标头和生成的JWT 代码)、/jwt/authenticatejwt/extendtoken 端点工作正常。

现在我需要将 OAuth2 身份验证服务设置为/googleauth/hello 端点,并将 LDAP 身份验证服务设置为/ldapauth/hello。 当我调用端点/googleauth/hello 时,它还会重定向到 LDAP 登录页面,而不是 Google 帐户选择页面。

【问题讨论】:

这能回答你的问题吗? Spring multiple authentication methods for different api endpoints 是的,有点类似,但那个答案对我不起作用。我将使用迄今为止所做的新配置来编辑我的问题。如果您对此有好主意,请帮助我。因为我是 Spring Security 的初学者。 @ThisaraJayaweera 您的问题是两个登录页面使用相同的 URL /login。尝试更改登录页面的 URL。 这能回答你的问题吗? Spring Security 3.2.1 Multiple login forms with distinct WebSecurityConfigurerAdapters @dur 我认为我的问题是 .antMatcher("/ldapauth/**") 没有按预期工作。我需要过滤所有 /ldapauth/** 模式并使用 ldap 身份验证方法。 【参考方案1】:

最后这个解决方案对我有用。我必须更改我的安全配置,如下所示。

@Configuration
@EnableWebSecurity
public class SecurityConfigure extends WebSecurityConfigurerAdapter 


    @Configuration
    @Order(1)
    public static class JwtWebSecurityConfig extends WebSecurityConfigurerAdapter
        @Autowired
        private AuthService authService;

        @Autowired
        private JwtRequestFilter jwtRequestFilter;

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception 
            auth.userDetailsService(authService);
        

        @Override
        protected void configure(HttpSecurity http) throws Exception 
            http
                    .csrf().disable()
                    .requestMatchers().antMatchers("/jwt/**")
                    .and()
                    .authorizeRequests().antMatchers("/jwt/authenticate").permitAll()
                    .anyRequest().authenticated()
                    .and().sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS);

            http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);

        

        @Override
        @Bean
        public AuthenticationManager authenticationManagerBean() throws Exception 
            return super.authenticationManagerBean();
        

        @Bean
        public PasswordEncoder passwordEncoder()
            return NoOpPasswordEncoder.getInstance();
        
    

    @Configuration
    @Order(2)
    public static class LdapSecurityConfig extends WebSecurityConfigurerAdapter
                @Override
                public void configure(AuthenticationManagerBuilder auth) throws Exception 
                    auth
                            .ldapAuthentication()
                            .userDnPatterns("uid=0,ou=people")
                            .groupSearchBase("ou=groups")
                            .contextSource()
                            .url("ldap://localhost:8389/dc=springframework,dc=org")
                            .and()
                            .passwordCompare()
                            .passwordEncoder(new BCryptPasswordEncoder())
                            .passwordAttribute("userPassword");
                

                @Override
                protected void configure(HttpSecurity http) throws Exception 
                    http
                            .csrf().disable()
                            .requestMatchers().antMatchers("/ldap/**","/login")
                            .and()
                            .authorizeRequests().antMatchers("/login").permitAll()
                            .anyRequest().fullyAuthenticated()
                            .and()
                            .formLogin();
                
    

    @Configuration
    @Order(3)
    public static class Oauth2SecurityConfig extends WebSecurityConfigurerAdapter

        @Override
        protected void configure(HttpSecurity http) throws Exception 
            http
                    .csrf().disable()
                    .requestMatchers().antMatchers("/google/**","/oauth2/**","/login/oauth2/**")
                    .and()
                    .authorizeRequests().antMatchers("/oauth2/**","/login/oauth2/**").permitAll()
                    .anyRequest().fullyAuthenticated()
                    .and()
                    .oauth2Login();
        
    


【讨论】:

以上是关于具有多种身份验证方法的 Web 安全设置的主要内容,如果未能解决你的问题,请参考以下文章

Rest Web 服务:具有令牌安全性的匿名和经过身份验证的用户

配置web服务基本用户身份验证,保证web站点的安全

这种基于 JWT 的身份验证方法安全吗?

Spring(引导)具有允许资源的安全预身份验证仍然经过身份验证

java- 哪种方式易于实现且安全,用于 Web 应用程序/Web 服务中的最终用户身份验证

Web API 身份验证最佳实践