使用 Basic Auth 针对另一个应用程序对 Springboot 应用程序进行身份验证

Posted

技术标签:

【中文标题】使用 Basic Auth 针对另一个应用程序对 Springboot 应用程序进行身份验证【英文标题】:Authenticate a Springboot Application against another application using Basic Auth 【发布时间】:2018-02-22 14:29:05 【问题描述】:

如何针对第三方应用程序对 Spring Boot 应用程序进行身份验证?

根据使用 spring security 实现基本身份验证的示例,验证了用户和密码,但我想针对来自另一个服务的 200 响应进行验证。 以下是对用户进行身份验证的方式: 用户使用基本身份验证发送凭据以访问我的 SpringBoot REST 服务 -> SpringBoot 服务向第三方服务发出带有基本身份验证标头的 GET 请求 -> 收到 200 OK 并验证最终用户以访问我的 REST 服务上的所有 URL。

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter 

    @Autowired
    private AuthenticationEntryPoint authEntryPoint;

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http.csrf().disable().authorizeRequests()
                .anyRequest().authenticated()
                .and().httpBasic()
                .authenticationEntryPoint(authEntryPoint);
    

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception 
        auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
    


【问题讨论】:

你试过什么? - 欢迎来到 ***。请阅读我们的How to Ask 页面以获取有关如何改进您的问题的提示。好的问题往往会从社区中提供更快、更好的答案 如果还没有,也可以take the tour 我是springboot的新手。我正在寻找可以尝试的示例。 那么这不是它的网站。请阅读我们的How to Ask 页面。 【参考方案1】:

您必须实现自己的AuthenticationProvider。例如:

public class ThirdPartyAuthenticationProvider implements AuthenticationProvider 

    @Override
    public Authentication authenticate(Authentication auth) thows AuthenticationException 
        // call third party site with auth.getPrincipal() and auth.getCredentials() (those are username and password)
        // Throw AuthenticationException if response is not 200
        return new UsernamePasswordAuthenticationToken(...);
    

    @Override
    public boolen supports(Class<?> authCls) 
        return UsernamePasswordAuthenticationToken.class.equals(authCls);
    

之后,您可以在 SpringSecurityConfig 中覆盖 configure(AuthenticationManagerBuilder) 方法:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception 
    // authProvider = instance of ThirdPartyAuthenticationProvider
    auth.authenticationProvider(authProvider); 

【讨论】:

【参考方案2】:

我使用 UserDetailsS​​ervice 让它工作。我创建了一个休息模板并调用我的第三方服务来验证用户,在收到响应后,用户可以访问所有请求。我就是这样做的:

SecurityConfig.java

    @Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter 

    @Autowired
    private AuthenticationEntryPoint authEntryPoint;

    protected void configure(HttpSecurity http) throws Exception 

        http.csrf().disable().authorizeRequests().anyRequest().authenticated().and().httpBasic()
                .authenticationEntryPoint(authEntryPoint);

    

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth, UserDetailsService userDetailsService)
            throws Exception 

        auth.userDetailsService(userDetailsService);
    

ABCUserDetails.java

    @Service("userDetailsService")
public class ABCUserDetails implements UserDetailsService 

    @Autowired
    private UserService userService;

    @Override
    public UserDetails loadUserByUsername(String abcuser) throws UsernameNotFoundException 
        // TODO Auto-generated method stub

        Map<String, Object> userMap = userService.getUserByUsername(abcuser);

        // check if this user with this username exists, if not, throw an
        // exception
        // and stop the login process
        if (userMap == null) 
            throw new UsernameNotFoundException("User details not found : " + abcuser);
        

        String username = (String) userMap.get("username");
        String password = (String) userMap.get("password");
        String role = (String) userMap.get("role");

        List<SimpleGrantedAuthority> authList = getAuthorities(role);

        User user = new User(username, password, authList);

        return user;

    

    private List<SimpleGrantedAuthority> getAuthorities(String role) 
        List<SimpleGrantedAuthority> authList = new ArrayList<>();
        authList.add(new SimpleGrantedAuthority("ROLE_USER"));

        if (role != null && role.trim().length() > 0) 
            if (role.equals("myrole")) 
                authList.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
            
        

        return authList;
    

用户服务.java

@Service("userService")
public class UserService 

    public Map<String, Object> getUserByUsername(String username) 
        // TODO Auto-generated method stub

        Map<String, Object> userMap = null;
//get current request attributes
        ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();

        String authToken = attr.getRequest().getHeader("Authorization");
        final String encodedUserPassword = authToken.replaceFirst("Basic" + " ", "");
        String usernameAndPassword = null;
        try 
            byte[] decodedBytes = Base64.getDecoder().decode(encodedUserPassword);
            usernameAndPassword = new String(decodedBytes, "UTF-8");
         catch (IOException e) 
            e.printStackTrace();
        
        final StringTokenizer tokenizer = new StringTokenizer(usernameAndPassword, ":");
        final String username1 = tokenizer.nextToken();
        final String password = tokenizer.nextToken();
//thirdparty url
        final String uri = "http://abcurlauthprovider/userid="
                + "\"" + username1 + "\"";

        RestTemplate restTemplate = new RestTemplate();
        try 
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            headers.add("Authorization", "Basic " + encodedUserPassword);
            HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
            ResponseEntity<String> mresponse = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class);

            if (username.equals(username1) || username.equals(username1)) 
                userMap = new HashMap<>();
                userMap.put("username", username1);
                userMap.put("password", password);
                userMap.put("role", (username.equals(username1)) ? username1 : username1);
                // return the usermap
                return userMap;
            
         catch (Exception eek) 
            System.out.println("** Exception: " + eek.getMessage());
        

        return null;
    


这是我的 AuthenticatioEntryPoint.java

    @Component
public class AuthenticationEntryPoint extends BasicAuthenticationEntryPoint 

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authEx)
            throws IOException, ServletException 

        response.addHeader("WWW-Authenticate", "Basic realm=" + getRealmName());
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        PrintWriter writer = response.getWriter();
        writer.println("HTTP Status 401 - " + authEx.getMessage());

    

    @Override
    public void afterPropertiesSet() throws Exception 

        System.out.println("----------------------inside afterPropertiesSet method");
        setRealmName("MYAPI");
        super.afterPropertiesSet();
    

【讨论】:

以上是关于使用 Basic Auth 针对另一个应用程序对 Springboot 应用程序进行身份验证的主要内容,如果未能解决你的问题,请参考以下文章

使用nginx的auth_basic实现prometheus 安全认证

如何在 Play Framework 1.2 中实现 HTTP Basic Auth?

Jmeter实现Basic Auth方式登录

Basic Auth不适用于多个配置

PHP Digest/Basic Auth 默认窗口外观

Nginx 访问认证