如何在Spring Boot中将RESTful与基本身份验证结合使用

时间:2019-01-03 09:00:35

标签: java rest basic-authentication restful-authentication spring-rest

Helllo,我正在使用具有基本身份验证的RESTful,并且此代码是RestController的一部分:

@GetMapping("/jpa/users/{username}/goals")
public List<Goal> getAllGoals(@PathVariable String username) {
    userId = getUserIdFromUsername(username);
    return goalJpaRepository.findByUserId(userId); 
}

public Long getUserIdFromUsername(String username) {
    User user = userJpaRepository.findByUsername(username);
    userId = user.getId(); 
    return userId;
}

我有一个问题,例如我正在使用邮递员来为特定用户检索目标,如下所示:

http://localhost:8080/jpa/users/john/goals(带有GET请求)

然后,我对用户名john使用基本身份验证,并为此用户名使用密码,然后我收到了john的目标。

此后,如果我对此链接http://localhost:8080/jpa/users/tom/goals进行GET请求,我就收到了Tom的目标,但是此时我已与john登录,因此john可以看到他的目标,并且他可以看汤姆的目标。

问题是我如何在RestController中访问登录用户名,因为我想执行以下操作:

if (loginUsername == username) {
    return goalJpaRepository.findByUserId(userId);
} 

return "Access denied!";

所以我想知道是否可以从HTTP标头访问登录用户名?

谢谢!


更新-是的,框架是Spring Boot,而且我正在使用带有Dao身份验证的Spring Security,因为我想从MySQL数据库中获取用户。无论如何,我不是Spring Security的专家。

现在,我了解了如何在控制器方法中使用Principal,但是对于这种特定情况,我不知道如何使用Spring Security。我应该如何实施?例如,用户john应该只看到和修改他的目标。

Spring安全配置:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
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.crypto.bcrypt.BCryptPasswordEncoder;

import com.dgs.restful.webservices.goaltrackerservice.user.MyUserDetailsService;

@Configuration
@EnableWebSecurity
public class SpringSecurityConfigurationBasicAuth extends WebSecurityConfigurerAdapter {

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    private MyUserDetailsService userDetailsService;

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider
          = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService);
        authProvider.setPasswordEncoder(bCryptPasswordEncoder());
        return authProvider;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http
            .csrf().disable()
            .authorizeRequests()
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            .antMatchers("/allusers").permitAll()
                .anyRequest().authenticated()
                .and()
            // .formLogin().and()
            .httpBasic();
        }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider());
    }
}

5 个答案:

答案 0 :(得分:1)

请注意,您目前不进行任何安全保护。

如@Matt 所说,“这取决于您使用的是哪个框架” 。但是我想你正在使用弹簧。然后,您应该查看spring-securuty模块的文档。

基本上,您可以将经过身份验证的用户注入到您的方法参数中:

   @GetMapping("/jpa/users/{username}/goals")
   public List<Goal> getAllGoals(@PathVariable String username, Principal principal) {
     if ( username.equals(principal.getName()) ) {
       userId = getUserIdFromUsername(username);
       return goalJpaRepository.findByUserId(userId); 
     } else {
       throw new SomeExceptionThatWillBeMapped();
     }
   } 

但是spring-security和许多框架提供了更好的模式来管理安全性。

答案 1 :(得分:1)

假设您将Spring用作Java框架,则应使用Spring安全性来配置基本身份验证。在线提供了许多教程(https://www.baeldung.com/spring-security-basic-authentication

然后,Spring Security将提供整个应用程序(SecurityContextHolder.getContext())可用的安全上下文,您可以从中检索连接的用户信息(用户名,...)。

例如,要检索所连接用户的用户名,您应该执行以下操作:

Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String loginUsername = authentication.getName();

或者,如@ gervais.b所述,Spring可以在控制器方法中注入Principal(或Authentication)。

@Glains所说,还有一个更好的选择是使用@PreAuthorize@PostAuthorize批注,这使您可以基于Spring Expression Language定义简单的规则。

答案 2 :(得分:1)

您还可以使用@PreAuthorize解决此问题,@PreAuthorize("principal.name == #username") @GetMapping("/jpa/users/{username}/goals") public List<Goal> getAllGoals(@PathVariable String username) { return goalJpaRepository.findByUserId(userId); } 是由Spring Security Framework提供的使用Spring表达式语言的注释。

SecurityContextHolder

在后台,Spring将使用已经提到的403来获取当前已认证的主体。如果该表达式解析为false,则将返回响应代码@Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration { }

请注意,您必须启用全局方法安全性:

from airflow.contrib.hooks.aws_hook import AwsHook
import boto3
hook = AwsHook(aws_conn_id=‘aws_default’)
    client = hook.get_client_type(‘emr’, ‘eu-central-1’)
    for x in a:
        print(x[‘Status’][‘State’],x[‘Name’])

答案 3 :(得分:1)

要回答有关“ Dao身份验证” 的新问题,答案是提供自定义UserDetailsService

从您附加到问题的配置来看,您似乎已经拥有MyUserDetailsService

有很多文章介绍了如何使用自定义DetailsService。这似乎符合您的要求:https://www.baeldung.com/spring-security-authentication-with-a-database

编辑:关于如何确保只有John可以看到John的项目的信息。

基本上,您可以采取的唯一措施是确保只有约翰才能看到他的目标,这是将目标限制为仅由约翰拥有的目标。但是有很多方法可以做到这一点。

  1. 正如您在最初的问题中建议的那样,您只需为特定用户选择目标即可。 spring-security的功能在于它可以注入Principal,但也可以注入其他身份验证对象。

  2. 还可以通过使用SecurityContextHolder使DAO /存储库端的过滤器更隐式。当您的系统更以用户为中心或像多租户系统时,这种方法很好并且看起来更好。

  3. 使用某些特定的@Annotations或Aspects也是一种解决方案,但在这种情况下可能不太明显。

答案 4 :(得分:0)

答案之前已经给出了答案。我只想补充一下,看看这篇文章。您可以使用json网络令牌轻松实现spring security:

https://auth0.com/blog/implementing-jwt-authentication-on-spring-boot/