我有 2 个微服务。具有 JWT 身份验证的 API 网关和管理各个用户模板的微服务。我的目标是用户只能看到他的模板。但我不清楚我是如何做到的。我是否必须生成额外的 ID token ,或者我也可以使用 feign 解决问题吗?
@GetMapping("/templates/{name}/{template_id}")
public Template retrieveTemplate(@PathVariable("name") String name,@PathVariable("template_id") int template_id)
{
return templateRepository.findByTemplateIdAndName(template_id, name);
}
这是我的获取方法,能够显示相应的模板。但是,我不希望 REST 中需要用户名。身份验证后,应该可以使用 token 来输出用户特定的数据,或者?我还有两个数据库表。一种用于身份验证,一种用于模板。在身份验证表中,我曾经拥有数据用户名和密码以及用户名。在模板表中,我只有用户名(以保持表较小)。这意味着,在从模板获取请求的情况下,必须从身份验证微服务请求用户的名称,以便能够仅显示用户的模板。有人可以告诉我哪种技术最适合我吗?
@Service
public class JwtUtil {
private String SECRET_KEY = "helloworld";
public String extractUsername(String token)
{
return extractClaim(token, Claims::getSubject);
}
public Date extractExpiration(String token)
{
return extractClaim(token, Claims::getExpiration);
}
public <T> T extractClaim(String token, Function<Claims,T> claimsResolver)
{
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
private Claims extractAllClaims(String token)
{
return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
}
private Boolean isTokenExpired(String token)
{
return extractExpiration(token).before(new Date());
}
public String generateToken(UserDetails userDetails)
{
Map<String,Object> claims =new HashMap<>();
return createToken(claims,userDetails.getUsername());
}
private String createToken(Map<String, Object> claims, String subject)
{
return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 1000*60*60*24*360))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact();
}
public Boolean validateToken(String token, UserDetails userDetails)
{
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
}
package sendMessage.LoginJwtAPIGateway;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
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.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@EnableWebSecurity
public class SecurityConfigurer extends WebSecurityConfigurerAdapter{
@Autowired
private MyUserDetailsService myUserDetailsService;
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Autowired
UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.userDetailsService(myUserDetailsService);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests().antMatchers("/authenticate").permitAll().
antMatchers("/users").hasRole("ADMIN")
.anyRequest().authenticated()
.and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception
{
return super.authenticationManagerBean();
}
@Bean
public BCryptPasswordEncoder getBCryptPasswordEncoder()
{
return new BCryptPasswordEncoder();
}
}
@Component
public class JwtRequestFilter extends OncePerRequestFilter{
@Autowired
private MyUserDetailsService userDetailsService;
@Autowired
private JwtUtil jwtUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
final String authorizationHeader =request.getHeader("Authorization");
String username = null;
String jwt = null;
if(authorizationHeader !=null && authorizationHeader.startsWith("Bearer "))
{
jwt = authorizationHeader.substring(7);
username= jwtUtil.extractUsername(jwt);
}
if (username != null && SecurityContextHolder.getContext().getAuthentication()==null)
{
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if (jwtUtil.validateToken(jwt, userDetails))
{
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
chain.doFilter(request,response);
}
}
package sendMessage.LoginJwtAPIGateway;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
public class MyUserDetails implements UserDetails{
private String username;
private String password;
private boolean active;
private List<GrantedAuthority> authorities;
public MyUserDetails()
{
}
public MyUserDetails(User user) {
this.username=user.getUsername();
this.password=user.getPassword();
this.active=user.isActive();
this.authorities =Arrays.stream(user.getRoles().split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
// TODO Auto-generated method stub
return authorities;
}
@Override
public String getPassword() {
// TODO Auto-generated method stub
return password;
}
public String getUsername() {
// TODO Auto-generated method stub
return username;
}
@Override
public boolean isAccountNonExpired() {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean isAccountNonLocked() {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean isCredentialsNonExpired() {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean isEnabled() {
// TODO Auto-generated method stub
return active;
}
}
最佳答案
如果您使用 Spring 和 JWT 生成 token ,那么您可以向 JWT 添加 token 增强器, token 增强器允许您向 token 添加其他信息。
然后您可以将用户名或用户 ID 添加到您的 token 中。
在调用模板端点时,您可以删除网址的名称部分。并依靠收到的 token 来获取用户名。
您可以在此处找到如何添加 token 增强器 https://www.baeldung.com/spring-security-oauth-jwt
关于java - 身份验证后如何显示用户特定数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59982273/