Java 如何在其他服务实现中从SpringSecurity接收经过身份验证的用户,而不是匿名用户。(SpringSecurity+;JWT)
你好,开发者。 我正在尝试在我的应用程序中检索经过身份验证的用户的一些数据,以便在其他方法中实现它。此应用程序使用Spring Security和JWT,因此首先要做的是在类UserDetailsImple上设置Java接口UserDetails的实现,如下所示:Java 如何在其他服务实现中从SpringSecurity接收经过身份验证的用户,而不是匿名用户。(SpringSecurity+;JWT),java,spring-boot,spring-security,jwt,Java,Spring Boot,Spring Security,Jwt,你好,开发者。 我正在尝试在我的应用程序中检索经过身份验证的用户的一些数据,以便在其他方法中实现它。此应用程序使用Spring Security和JWT,因此首先要做的是在类UserDetailsImple上设置Java接口UserDetails的实现,如下所示: package com.example.demo.services; import com.example.demo.entiities.Renter; import com.fasterxml.jackson.annotation
package com.example.demo.services;
import com.example.demo.entiities.Renter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.*;
import java.util.stream.Collectors;
public class UserDetailsImpl implements UserDetails {
public static final long serialVersionUID=1L;
private Long id;
private String username;
private String email;
@JsonIgnore
private String password;
private Collection<? extends GrantedAuthority> authorities;
public UserDetailsImpl(Long id, String username, String email, String password,
Collection<? extends GrantedAuthority> authorities) {
this.id = id;
this.username = username;
this.email = email;
this.password = password;
this.authorities = authorities;
}
public static UserDetailsImpl build(Renter renter) {
List<GrantedAuthority> authorities = renter.getRoles().stream()
.map(role -> new SimpleGrantedAuthority(renter.getRenterName()))
.collect(Collectors.toList());
return new UserDetailsImpl(
renter.getId(),
renter.getRenterName(),
renter.getRenbterEmail(),
renter.getRenterPassword(),
authorities);
}//this method would return the new user logged details accessed through the entity Renter and each
//method i need neccesary for my app comsumption , like getting the name , email, password,etc...
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
public Long getId() {
return id;
}
public String getEmail() {
return email;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
UserDetailsImpl user = (UserDetailsImpl) o;
return Objects.equals(id, user.id);
}
}
因此,下一步将设置所有逻辑以过滤在每个用户登录请求中创建的令牌,
通过生成该令牌并触发SecurityContextHolder,我可能能够访问用户验证的详细信息,因此:
package com.example.demo.jwt;
import com.example.demo.services.UserDetailsServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class AuthTokenFilter extends OncePerRequestFilter {
@Autowired
private JwtUtils jwtUtils;
@Autowired
private UserDetailsServiceImpl userDetailsService;
private static final Logger logger = LoggerFactory.getLogger(AuthTokenFilter.class);
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
try {
String jwt = parseJwt(request);
if (jwt != null && jwtUtils.validateJwtToken(jwt)) {
String username = jwtUtils.getUserNameFromJwtToken(jwt);
UserDetails userDetails = userDetailsService.loadUserByUsername(username)
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception e) {
logger.error("Cannot set user authentication: {}", e);
}
filterChain.doFilter(request, response);
}
Thus in this case basically inside the try statement under the condition of the generated token being valid , first i extract the user name from the token . Then from that username i got the UserDetails to create an Authentication object accessing the method of its service(loadUserByname); and after that
got settled the current UserDetails in SecurityContext using setAuthentication(authentication) method, that would be used in further implemenbtations to access the user data(didn't work)
private String parseJwt(HttpServletRequest request) {
String headerAuth = request.getHeader("Authorization");
if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {
return headerAuth.substring(7, headerAuth.length());
}
return null;
}
}
然后,通过用户交互创建登录有效负载,以实现身份验证所需的所有数据
类LoginRequest上的进程。
服务的登录实现及其实现将以这种方式设置
RENTER SERVICE
package com.example.demo.services;
import com.example.demo.entiities.Renter;
import com.example.demo.exceptions.GeneralException;
import com.example.demo.payload.LoginRequest;
import org.springframework.http.ResponseEntity;
import java.util.List;
import java.util.Map;
public interface RenterService {
ResponseEntity<?> loginUser(LoginRequest loginRequest)throws GeneralException;
}
RENTER SERVICE IMPLEMENTATION
package com.example.demo.services;
import com.example.demo.dto.RenterDtos;
import com.example.demo.entiities.EnumRoles;
import com.example.demo.entiities.Renter;
import com.example.demo.entiities.Role;
import com.example.demo.exceptions.GeneralException;
import com.example.demo.exceptions.NotFoundException;
import com.example.demo.jsons.RenterJson;
import com.example.demo.jwt.JwtUtils;
import com.example.demo.payload.LoginRequest;
import com.example.demo.payload.SignUprequest;
import com.example.demo.repositories.RenterRepository;
import com.example.demo.repositories.RoleRepository;
import com.example.demo.responses.JwtResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.client.HttpServerErrorException;
import java.util.*;
import java.util.stream.Collectors;
import org.modelmapper.ModelMapper;
import javax.validation.Valid;
@Service
public class RenterServiceImpl implements RenterService {
@Autowired
private RenterRepository renterRepository;
@Autowired
private RoleRepository roleRepository;
@Autowired
PasswordEncoder passwordEncoder;
@Autowired
AuthenticationManager authenticationManager;
@Autowired
JwtUtils jwtUtils;
private static final Logger LOGGER = LoggerFactory.getLogger(RenterServiceImpl.class);
@Override
public ResponseEntity<?> loginUser(LoginRequest loginRequest) throws GeneralException {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getRenterName(), loginRequest.getRenterPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = jwtUtils.generateJwtToken(authentication);
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
List<String> roles = userDetails.getAuthorities().stream()
.map(item -> item.getAuthority())
.collect(Collectors.toList());
return ResponseEntity.ok(new JwtResponse(jwt,
userDetails.getId(),
userDetails.getUsername(),
userDetails.getEmail(),
roles));
}
private static List<GrantedAuthority> mapRoleUser(List<String> roles){
List<GrantedAuthority>authorities=new ArrayList<>();
for (String role : roles){
authorities.add(new SimpleGrantedAuthority(role));
}
return authorities;
}
}
老实说,我完全不知道还能做什么!。
在我的调试过程中,为了检查:
选择1
选择2
最后但并非最不重要的一点是,在我的安全包中,它的类是这样设置的:
package com.example.demo.security;
import com.example.demo.entiities.Renter;
import com.example.demo.exceptions.NotFoundException;
import com.example.demo.jwt.AuthEntryPointJwt;
import com.example.demo.jwt.AuthTokenFilter;
import com.example.demo.repositories.RenterRepository;
import com.example.demo.services.ProductServiceImpl;
import com.example.demo.services.RenterService;
import com.example.demo.services.UserDetailsImpl;
import com.example.demo.services.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
// securedEnabled = true,
// jsr250Enabled = true,
prePostEnabled = true)public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
RenterService renterService;
@Autowired
UserDetailsServiceImpl userDetailsService;
@Autowired
ProductServiceImpl productService;
@Autowired
private AuthEntryPointJwt unauthorizedHandler;
@Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
return new AuthTokenFilter();
}
@Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/cubancoder/multirenter/**","/v2/api-docs","/configuration/ui",
"/swagger-resources/**",
"/configuration/security",
"/swagger-ui.html",
"/webjars/**").permitAll()
.antMatchers("/api/test/**").permitAll()
.anyRequest().authenticated();
http.logout().logoutUrl("/cubancoder/multirenter/logout");
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
任何帮助都将是惊人的。请 不要实现自己的jwt令牌过滤器,而是使用spring security提供的过滤器。谢谢你回答我的问题,但是你能解释一下用哪种方式修改这个问题吗?,,,,提前谢谢,老实说,我不知道如何在我的代码中处理它。你能解释多一点吗?…谢谢!!!我没有费心去看你的代码,因为你不应该实现一个定制的JWT过滤器。构建自定义安全身份验证是一种糟糕的做法。使用Spring提供的经过全面测试和安全的工具,如果遇到问题,请返回。不要实现自己的jwt令牌筛选器,请使用Spring security提供的工具。谢谢你回答我的问题,但是你能解释一下用哪种方式修改这个问题吗?,,,,提前谢谢,老实说,我不知道如何在我的代码中处理它。你能解释多一点吗?…谢谢!!!我没有费心去看你的代码,因为你不应该实现一个定制的JWT过滤器。构建自定义安全身份验证是一种糟糕的做法。使用Spring提供的工具,这些工具经过充分测试并安全可靠,如果遇到问题,请返回。
package com.example.demo.controller;
import com.example.demo.dto.RenterRegisterDto;
import com.example.demo.entiities.EnumRoles;
import com.example.demo.jsons.CreateRenterJson;
import com.example.demo.jsons.RenterJson;
import com.example.demo.jwt.JwtUtils;
import com.example.demo.payload.LoginRequest;
import com.example.demo.payload.SignUprequest;
import com.example.demo.repositories.RenterRepository;
import com.example.demo.repositories.RoleRepository;
import com.example.demo.responses.AppResponse;
import com.example.demo.entiities.Renter;
import com.example.demo.entiities.Role;
import com.example.demo.exceptions.GeneralException;
import com.example.demo.responses.JwtResponse;
import com.example.demo.services.RenterService;
import com.example.demo.services.UserDetailsImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.*;
import java.util.stream.Collectors;
@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/cubancoder/multirenter")
public class RegistrationController {
@Autowired
RenterService renterService;
@Autowired
AuthenticationManager authenticationManager;
@Autowired
RenterRepository renterRepository;
@Autowired
RoleRepository roleRepository;
@Autowired
PasswordEncoder passwordEncoder;
@Autowired
JwtUtils jwtUtils;
@ResponseStatus(HttpStatus.OK)
@PostMapping(value = "/login/renter")
public AppResponse<ResponseEntity<?>> logInUser(@Valid @RequestBody LoginRequest loginRequest) throws GeneralException {
return new AppResponse<>("Success",String.valueOf(HttpStatus.CREATED),
"Ok",renterService.loginUser(loginRequest));
}
}
package com.example.demo.services;
import com.example.demo.dto.ProductDtos;
import com.example.demo.dto.RenterDtos;
import com.example.demo.entiities.*;
import com.example.demo.exceptions.GeneralException;
import com.example.demo.exceptions.NotFoundException;
import com.example.demo.jwt.AuthEntryPointJwt;
import com.example.demo.jwt.JwtUtils;
import com.example.demo.payload.LoginRequest;
import com.example.demo.repositories.ProductRepository;
import com.example.demo.repositories.RenterRepository;
import com.example.demo.security.AuthenticationValidation;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
ProductRepository productRepository;
@Autowired
AuthenticationManager authenticationManager;
@Autowired
UserDetailsService userDetailsService;
@Autowired
ProductDtos productDtos;
@Autowired
AuthEntryPointJwt authEntryPointJwt;
@Autowired
RenterDtos renterDtos;
@Autowired
RenterRepository renterRepository;
@Autowired
JwtUtils jwtUtils;
@Autowired
LoginRequest loginRequest;
public Map<String, Object> getAllProducts() throws GeneralException {
Map<String, Object> dto = new HashMap<>();
List<Product> listProducts = productRepository.findAll();
Option1:
Object auth = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
.....doing something here .........
Option2:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth.isAuthenticated()) {
Object Authenticated = auth.getPrincipal();
String renterLogged = ((UserDetails) Authenticated).getUsername();
.....doing something........
}
return dto;
}
}
ava.lang.ClassCastException: java.lang.String cannot be cast to org.springframework.security.core.userdetails.UserDetails
at com.example.demo.services.ProductServiceImpl.getAllProducts(ProductServiceImpl.java:83) ~[classes/:na]...
package com.example.demo.security;
import com.example.demo.entiities.Renter;
import com.example.demo.exceptions.NotFoundException;
import com.example.demo.jwt.AuthEntryPointJwt;
import com.example.demo.jwt.AuthTokenFilter;
import com.example.demo.repositories.RenterRepository;
import com.example.demo.services.ProductServiceImpl;
import com.example.demo.services.RenterService;
import com.example.demo.services.UserDetailsImpl;
import com.example.demo.services.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
// securedEnabled = true,
// jsr250Enabled = true,
prePostEnabled = true)public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
RenterService renterService;
@Autowired
UserDetailsServiceImpl userDetailsService;
@Autowired
ProductServiceImpl productService;
@Autowired
private AuthEntryPointJwt unauthorizedHandler;
@Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
return new AuthTokenFilter();
}
@Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/cubancoder/multirenter/**","/v2/api-docs","/configuration/ui",
"/swagger-resources/**",
"/configuration/security",
"/swagger-ui.html",
"/webjars/**").permitAll()
.antMatchers("/api/test/**").permitAll()
.anyRequest().authenticated();
http.logout().logoutUrl("/cubancoder/multirenter/logout");
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
}