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());
}
}
答案 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的项目的信息。
基本上,您可以采取的唯一措施是确保只有约翰才能看到他的目标,这是将目标限制为仅由约翰拥有的目标。但是有很多方法可以做到这一点。
正如您在最初的问题中建议的那样,您只需为特定用户选择目标即可。 spring-security的功能在于它可以注入Principal
,但也可以注入其他身份验证对象。
还可以通过使用SecurityContextHolder
使DAO /存储库端的过滤器更隐式。当您的系统更以用户为中心或像多租户系统时,这种方法很好并且看起来更好。
使用某些特定的@Annotations或Aspects也是一种解决方案,但在这种情况下可能不太明显。
答案 4 :(得分:0)
答案之前已经给出了答案。我只想补充一下,看看这篇文章。您可以使用json网络令牌轻松实现spring security:
https://auth0.com/blog/implementing-jwt-authentication-on-spring-boot/