我目前正在使用Spring Security开发Spring Boot REST应用程序。我的工作场所使用Auth0(提供用户管理的外部第三方服务)进行身份验证,并已要求我在此应用程序中实现它。身份验证发生在用React编写的前端应用程序中。前端应用程序显示登录表单,并将用户名和密码发送给Auth0,Auth0验证凭据,并在验证用户时返回JWT令牌。
在此之后,前端应用程序将通过Authorize
头中的JWT令牌从我的应用程序调用REST服务。Spring Security使用Auth0插件验证该令牌,并允许执行请求。我已经测试了这么多,以达到预期效果。代码如下:
import java.util.Arrays;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
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.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import com.auth0.spring.security.api.JwtWebSecurityConfigurer;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
@Value(value = "${auth0.apiAudience}")
private String apiAudience;
@Value(value = "${auth0.issuer}")
private String issuer;
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:8080"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
configuration.setAllowCredentials(true);
configuration.addAllowedHeader("Authorization");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors();
JwtWebSecurityConfigurer //Auth0 provided class performs per-authentication using JWT token
.forRS256(apiAudience, issuer)
.configure(http)
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/Test/public").permitAll()
.antMatchers(HttpMethod.GET, "/Test/authenticated").authenticated();
}
}
现在,一旦完成了身份验证,我发现安全上下文中的主体将使用Auth0中的用户id进行更新。我已经通过以下代码片段验证了这一点:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String name = authentication.getName(); // Returns the Auth0 user id.
我希望做的下一步是使用此用户id将用户与我现有数据库模式中的角色和权限匹配。因此,我需要实现一个自定义授权机制,该机制也可以插入到Spring Security中。换句话说,用户的角色必须在(预)身份验证完成后不久加载到安全上下文中。我该如何实现这一点?是否有一些类需要扩展或实现一些接口?
好吧,我找到了一个解决方案,虽然我觉得有点脏。按照官方Auth0类的奇怪结构,我所做的可能被描述为黑客行为。不管怎样,下面是:
首先,我通过实现AuthenticationUserDetailsService接口创建了一个自定义用户详细信息服务:
@Service
public class VUserDetailsService implements AuthenticationUserDetailsService<PreAuthenticatedAuthenticationJsonWebToken> {
@Autowired
UserRepository userRepository;
Logger logger = LoggerFactory.getLogger(VUserDetailsService.class);
@Override
@Transactional(readOnly = true)
public UserDetails loadUserDetails(PreAuthenticatedAuthenticationJsonWebToken token) throws UsernameNotFoundException {
logger.debug("User id: "+token.getName());
// Verify whether there is an entry for this id in the database.
User user = userRepository.findByAuxillaryId(token.getName());
if(user == null)
throw new UsernameNotFoundException("The user with id "+token.getName()+" not found in database.");
logger.debug("Obtained user details from db: "+user.toString());
List<GrantedAuthority> authoritiesList = new ArrayList<>();
// Get user roles
List<UserRole> userRoles = user.getUserRoles();
if(userRoles != null) logger.debug("Number of user roles:"+userRoles.size());
for(UserRole userRole : userRoles) {
logger.debug(userRole.getCompositeKey().getRole());
authoritiesList.add(new SimpleGrantedAuthority(userRole.getCompositeKey().getRole()));
}
return new org.springframework.security.core.userdetails.User(token.getName(), "TEMP", authoritiesList);
}
}
在这里,辅助id是在Auth0中创建用户时分配的用户id。请注意,预验证验证JsonWebToken
也是Auth0提供的类。
在这之后,我创建了一个自定义身份验证提供程序,扩展了Auth0提供的Jwt验证提供程序
:
public class VAuthenticationProvider extends JwtAuthenticationProvider {
public VAuthenticationProvider(JwkProvider jwkProvider, String issuer, String audience) {
super(jwkProvider, issuer, audience);
}
@Autowired
VUserDetailsService vUserDetailsService;
Logger logger = LoggerFactory.getLogger(VAuthenticationProvider.class);
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
logger.debug("*** Processing authentication for token: "+authentication.getName());
logger.debug("*** Current granted authorities: "+authentication.getAuthorities());
UserDetails userDetails = vUserDetailsService.loadUserDetails((PreAuthenticatedAuthenticationJsonWebToken) authentication);
authentication = new PreAuthenticatedAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities());
return authentication;
}
@Override
public boolean supports(Class<?> authentication) {
//com.auth0.spring.security.api.authentication.PreAuthenticatedAuthenticationJsonWebToken
return authentication.equals(PreAuthenticatedAuthenticationJsonWebToken.class);
}
}
然后我在我的安全配置类中使用了这个身份验证提供程序:
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Value(value = "${auth0.apiAudience}")
private String apiAudience;
@Value(value = "${auth0.issuer}")
private String issuer;
@Autowired
VUserDetailsService vUserDetailsService;
Logger log = LoggerFactory.getLogger(SecurityConfiguration.class);
@Bean
public VAuthenticationProvider authProvider() {
JwkProvider jwkProvider = new JwkProviderBuilder(issuer).build(); //Auth0 provided class
VAuthenticationProvider vAuthProvider = new VAuthenticationProvider(jwkProvider, issuer, apiAudience);
return vAuthProvider;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors();
JwtWebSecurityConfigurer.forRS256(apiAudience, issuer, authProvider())
.configure(http)
.authorizeRequests().antMatchers(HttpMethod.GET, "/Test/public").permitAll()
.antMatchers(HttpMethod.GET, "/Test/authenticated").authenticated()
.antMatchers(HttpMethod.GET, "/admin/*").hasRole("ADMIN") //Not Auth0 role, defined in my DB.
.antMatchers(HttpMethod.GET, "/Test/root").hasRole("ROOT"); //Not Auth0 role, defined in my DB.
}
/* Code ommitted */
现在,我的所有请求都会根据数据库中的角色进行筛选。因此,Auth0仅用于身份验证,授权基于数据库中的角色。
如果有人认为这个解决方案可以改进,请告诉我。
我想你要找的是AuthenticationProvider
接口。以下是我如何处理身份验证的两个示例:
DAO身份验证
@Component
public class DaoAdminAuthenticationProvider extends DaoAuthenticationProvider {
private static final Logger LOG =
LoggerFactory.getLogger(DaoAdminAuthenticationProvider.class);
private final AdminUserRepository adminUserRepository;
public DaoAdminAuthenticationProvider(AdminUserRepository adminUserRepository, DaoAdminUserDetailsService daoAdminUserDetailsService) {
this.adminUserRepository = adminUserRepository;
setPasswordEncoder(new BCryptPasswordEncoder(11));
this.setUserDetailsService(daoAdminUserDetailsService);
}
@Override
public Authentication authenticate(Authentication auth) throws AuthenticationException {
AdminUser adminUser = adminUserRepository.findByEmail(auth.getName());
if (adminUser == null) {
LOG.info("Invalid username or password");
throw new BadCredentialsException("Invalid username or password");
}
Authentication result = super.authenticate(auth);
return new UsernamePasswordAuthenticationToken(adminUser, result.getCredentials(), result.getAuthorities());
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
JwtAuthenticationProvider
@Component
public class JwtAuthenticationProvider implements AuthenticationProvider {
private static final Logger LOG =
LoggerFactory.getLogger(JwtAuthenticationProvider.class);
private static final String EX_TOKEN_INVALID = "jwt.token.invalid";
private final JwtTokenService jwtTokenService;
@SuppressWarnings("unused")
public JwtAuthenticationProvider() {
this(null);
}
@Autowired
public JwtAuthenticationProvider(JwtTokenService jwtTokenService) {
this.jwtTokenService = jwtTokenService;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
try {
String token = (String) authentication.getCredentials();
String username = jwtTokenService.getUsernameFromToken(token);
return jwtTokenService.validateToken(token)
.map(aBoolean -> new JwtAuthenticatedProfile(username))
.orElseThrow(() -> new TokenException(EX_TOKEN_INVALID));
} catch (JwtException ex) {
LOG.error("Invalid JWT Token");
throw new TokenException(EX_TOKEN_INVALID);
}
}
@Override
public boolean supports(Class<?> authentication) {
return JwtAuthentication.class.equals(authentication);
}
}
其他类,如JwtTokenService
等,我也实现了。但是关于你的问题,我认为答案是使用AuthenticationProvider
接口。
技术栈在前端是reactJS,后端由APIGateway和Lambda供电。我正在使用Auth0作为我的react应用程序中的身份服务。通过Auth0提供的一个社交登录进行身份验证时,我会返回、和。此外,我可以使用获取用户信息,例如。现在,我需要保护/阻止对我的后端即APIGateway和lambda的访问。 有很多选项来保护对AWS APIGateway的访问,如IAM授权器、自定义授权器。有一
我有自定义的身份验证筛选器,它创建PreAuthenticatedAuthenticationToken并将其存储在安全上下文中。过滤器工作良好,它创建具有相应授权权限的令牌“role_user”和“role_adminuser”。这是我的配置: 我将在SecurityContextPersistenceFilter之前插入过滤器,如:Spring security and custom Auth
我们使用Spring Security OAuth2保护我们的REST服务(用于服务器到服务器通信,不涉及用户)。但是,当您尝试访问浏览器中的受保护资源时,它将显示: 我们希望这是我们自己选择的自定义页面。有办法吗? 设置“拒绝访问”页面不起作用。首先,它需要定义一个登录页面,我们没有,因为这是一个纯服务器到服务器的通信。另一个原因是,这个属性自Spring 3.0..或类似的版本以来就被弃用了。
问题内容: 这是我的情况: 一个Web应用程序对许多应用程序执行某种SSO 登录的用户,而不是单击链接,该应用就会向正确的应用发布包含用户信息(名称,pwd [无用],角色)的帖子 我正在其中一个应用程序上实现SpringSecurity以从其功能中受益(会话中的权限,其类提供的方法等) 因此,我需要开发一个 自定义过滤器 -我猜想-能够从请求中检索用户信息,通过自定义 DetailsUserSe
我正在寻找如何使用以下设置测试Spring Boot REST API的方法: _ _ 我的测试用例: _ 不幸的是,我在测试中得到以下响应: 在请求之后,我还调试了不同的spring过滤器,其中SecurityContext身份验证为null,随后切换为AnonymousAuthenticationToken 我不知道为什么SecurityContext在请求后为null,而不是用@WithCu
功能说明 目睹直播提供了一系列的授权观看方式,如密码验证,付费观看等,然而由于客户业务的多样性,实现如:接入客户自身账户体系,登陆OA系统后再跳转到目睹观看直播等一系列更高级的授权观看方式,此时就需要使用自定义授权。 自定义授权逻辑图 功能设置 首先,需在 某个频道 - 频道管理 - 授权观看 - 授权类型 中点击自定义授权,并输入您希望在观众进入观看页时跳转的链接,如: http://your-