簡體   English   中英

如何在 Spring Boot 中將 RESTful 與基本身份驗證結合使用

[英]How to use RESTful with Basic Authentication in Spring Boot

你好,我使用 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;
}

我有一個問題,例如我使用 Postman 來檢索特定用戶的目標,如下所示:

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 Header訪問登錄用戶名?

謝謝!


更新- 是的,框架是 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());
    }
}

請注意,您目前不做任何安全保護。

正如@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和許多框架提供了更好的模式來管理安全性。

假設您將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定義簡單的規則。

您還可以使用@PreAuthorize解決此問題, @PreAuthorize是Spring Security Framework提供的使用Spring Expression Language的注釋。

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

在后台,Spring將使用已經提到的SecurityContextHolder來獲取當前已認證的主體。 如果表達式解析為假,則將返回響應代碼403

請注意,您必須啟用全局方法安全性:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {

}

要回答有關“ Dao身份驗證”的新問題,答案是提供一個自定義UserDetailsService

從附加到問題的配置來看,您似乎已經具有MyUserDetailsService

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

編輯 :關於如何確保只有約翰能看到約翰的物品。

基本上,您可以采取的唯一措施是確保只有約翰才能看到他的目標,這是將目標限制為僅由約翰擁有的目標。 但是有很多方法可以做到這一點。

  1. 正如您在最初的問題中所建議的那樣,您只需選擇特定用戶的目標即可。 spring-security的功能在於它可以注入Principal ,也可以注入其他身份驗證對象。

  2. 您還可以使用SecurityContextHolder使DAO /存儲庫端的過濾器更加隱式。 當您的系統更以用戶為中心或像多租戶系統時,這種方法很好並且看起來更好。

  3. 使用某些特定的@Annotations或Aspects也是一種解決方案,但在這種情況下可能不太明顯。

答案已經在答案之前給出了。 我只想補充一下,看看這篇文章。 您可以使用json網絡令牌輕松實現Spring安全性:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM