我是Spring Security的新手,我的Sping Boot 版本是2. 3. 11. RELEASE。
我使用MySQL作为数据库,使用SpringDataJPA来持久化实体。
我保存的用户没有任何角色。所以我不需要基于角色的身份验证。我只想验证输入的电子邮件和存储在我的数据库中的密码,但当我测试API时,Spring Security返回401“未授权”响应消息。
下面是我的代码片段。
用户类
@Entity
@ConfigurationProperties("user")
@JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
@Table(name = "users")
public class User implements Serializable, UserDetails {
@Id
private String id;
@NotBlank
private String name;
@Column(name = "phone_ext")
private String phoneExt;
@Column(name = "phone_no")
private String phoneNo;
@NotNull
private String email;
@NotNull
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "country")
private Country country;
@NotNull
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "currency")
private Currency currency;
@Column(name = "fb_id")
private String facebookId;
@Column(name = "google_id")
private String googleId;
@NotNull
@Column(name = "current_balance")
private int currentBalance;
@NotNull
@Column(name = "is_enabled")
private boolean enabled;
@NotNull
@Column(name = "free_sample_used")
private boolean isfreeSampleUsed;
@Column(name = "client_id")
private String clientId;
@JsonIgnore
@Column(name = "password", nullable = true)
private String password;
@Column(name = "coupons_used")
private String couponsUsed;
/**
* @return the userId
*/
public String getId() {
return id;
}
/**
* @param userId the userId to set
*/
public User setId(String userId) {
this.id = userId;
return this;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public User setName(String name) {
this.name = name;
return this;
}
/**
* @return the phoneExt
*/
public String getPhoneExt() {
return phoneExt;
}
/**
* @param phoneExt the phoneExt to set
*/
public User setPhoneExt(String phoneExt) {
this.phoneExt = phoneExt;
return this;
}
/**
* @return the phoneNo
*/
public String getPhoneNo() {
return phoneNo;
}
/**
* @param phoneNo the phoneNo to set
*/
public User setPhoneNo(String phoneNo) {
this.phoneNo = phoneNo;
return this;
}
/**
* @return the email
*/
public String getEmail() {
return email;
}
/**
* @param email the email to set
*/
public User setEmail(String email) {
this.email = email;
return this;
}
/**
* @return the country
*/
public Country getCountry() {
return country;
}
/**
* @param country the country to set
*/
public User setCountry(Country country) {
this.country = country;
return this;
}
/**
* @return the currency
*/
public Currency getCurrency() {
return currency;
}
/**
* @param currency the currency to set
*/
public User setCurrency(Currency currency) {
this.currency = currency;
return this;
}
/**
* @return the facebookId
*/
public String getFacebookId() {
return facebookId;
}
/**
* @param facebookId the facebookId to set
*/
public User setFacebookId(String facebookId) {
this.facebookId = facebookId;
return this;
}
/**
* @return the googleId
*/
public String getGoogleId() {
return googleId;
}
/**
* @param googleId the googleId to set
*/
public User setGoogleId(String googleId) {
this.googleId = googleId;
return this;
}
/**
* @return the currentBalance
*/
public int getCurrentBalance() {
return currentBalance;
}
/**
* @param currentBalance the currentBalance to set
*/
public User setCurrentBalance(int currentBalance) {
this.currentBalance = currentBalance;
return this;
}
/**
* @return the isEnabled
*/
public boolean isEnabled() {
return enabled;
}
/**
* @param isEnabled the isEnabled to set
*/
public User setEnabled(boolean enabled) {
this.enabled = enabled;
return this;
}
/**
* @return the isfreeSampleUsed
*/
public boolean isIsfreeSampleUsed() {
return isfreeSampleUsed;
}
/**
* @param isfreeSampleUsed the isfreeSampleUsed to set
*/
public User setIsfreeSampleUsed(boolean isfreeSampleUsed) {
this.isfreeSampleUsed = isfreeSampleUsed;
return this;
}
/**
* @return the clientId
*/
public String getClientId() {
return clientId;
}
/**
* @param clientId the clientId to set
*/
public User setClientId(String clientId) {
this.clientId = clientId;
return this;
}
/**
* @param password the password to set
*/
public User setPassword(String password) {
this.password = password;
return this;
}
/**
* @return the password
*/
@Override
public String getPassword() {
return this.password;
}
@Override
public String getUsername() {
return this.email;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return new HashSet<GrantedAuthority>();
}
@Override
public boolean isAccountNonExpired() {
return false;
}
@Override
public boolean isAccountNonLocked() {
return false;
}
@Override
public boolean isCredentialsNonExpired() {
return false;
}
/**
* @return the couponsUsed
*/
public String getCouponsUsed() {
return couponsUsed;
}
/**
* @param couponsUsed the couponsUsed to set
*/
public void setCouponsUsed(String couponsUsed) {
this.couponsUsed = couponsUsed;
}
public User() {
super();
this.id = null ;
this.name = "";
this.email = "";
this.country = new Country();
this.currency = new Currency();
this.currentBalance = 0;
this.enabled = true;
this.isfreeSampleUsed = false;
this.password = "";
}
/**
* To generate invoice id
*
* @return random UUID
*/
public String generateId() {
return UUID.randomUUID().toString();
}
}
控制器中的API端点
@PostMapping("/authenticate")
public ResponseEntity<IECAuthenticationResponse> createAuthenticationToken(@RequestBody IECAuthenticationRequestBody body,
@NotNull @RequestParam (value = "client_id", required = true)
String clientId){
IECAuthenticationResponse iecAuthenticationResponse = new IECAuthenticationResponse();
try {
boolean valid = EmailValidator.getInstance().isValid(body.getEmail());
if(!valid){
throw new PaperTrueInvalidEmailException("Invalid email address, please use a valid email address");
}
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(body.getEmail(), body.getPassword()));
UserDetails userDetails = myUserDetailsServices.loadUserByUsername(body.getEmail());
System.out.println("User Details username ----> " + userDetails.getUsername());
System.out.println("User Details Password ---> " + userDetails.getPassword());
User user = userService.getUserByEmail(body.getEmail());
if(!user.getClientId().equals(clientId)) {
throw new PaperTrueInvalidClientException("Invalid clientId, Please check the clientId");
}
boolean matches = passwordEncoder.matches(body.getPassword(), user.getPassword());
System.out.println("Matches --> " + matches);
if(matches) {
String token = jwtUtil.generateToken(userDetails);
iecAuthenticationResponse.setToken(token)
.setUserId(user.getId())
.setStatus(new Status("User authenticated successfully"));
}
} catch (PaperTrueUserNotFoundException | PaperTrueInvalidEmailException | PaperTrueInvalidClientException e) {
iecAuthenticationResponse.setStatus(new Status(e.getCode(), e.getMessage()));
}catch (BadCredentialsException e){
iecAuthenticationResponse.setStatus(new Status(e.getMessage()));
}
return ResponseEntity.ok(iecAuthenticationResponse);
我的用户详细信息服务类
@Service
public class MyUserDetailsServices implements UserDetailsService {
@Autowired
private UserService userService;
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
System.out.println("Inside loadByUserName function ------");
User emailInstance = null;
try {
System.out.println("------ Inside try block-------");
emailInstance = userService.getEmailInstance(email);
System.out.println("Email Instance ----> " + emailInstance);
} catch (PaperTrueUserNotFoundException e) {
emailInstance = null;
}
if(emailInstance == null){
throw new UsernameNotFoundException("User not found w.r.t given email");
}
System.out.println("Email ---> " + emailInstance.getEmail());
System.out.println("Password ---> " + emailInstance.getPassword());
return emailInstance;
}
}
安全配置类
@EnableWebSecurity
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
@Autowired
private JwtAuthenticationFilter jwtAuthenticationFilter;
@Autowired
private MyUserDetailsServices myUserDetailsServices;
@Override
protected void configure(HttpSecurity http) throws Exception {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedHeaders(
List.of("Authorization", "Cache-Control", "Content-Type", "X-PT-SESSION-ID", "NGSW-BYPASS"));
corsConfiguration.setAllowedOrigins(List.of("*"));
corsConfiguration
.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PUT", "OPTIONS", "PATCH", "DELETE"));
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setExposedHeaders(List.of("Authorization"));
http.csrf().disable()
.authorizeRequests()
.antMatchers("/iec/register", "/iec/authenticate").permitAll()
.anyRequest().authenticated().and()
.cors().configurationSource(request -> corsConfiguration)
.and().exceptionHandling().authenticationEntryPoint(unauthorizedHandler)
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsServices).passwordEncoder(encoder());
}
@Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// configure AuthenticationManager so that it knows from where to load
// user for matching credentials
// Use BCryptPasswordEncoder
auth.userDetailsService(myUserDetailsServices).passwordEncoder(encoder());
}
}
JwtAuthentication类别
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized 1");
}
}
JwtAuthenticationFilter类别
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private MyUserDetailsServices userDetailsService;
@Autowired
private JwtUtil jwtUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String header = request.getHeader("Authorization");
String userName = null;
String token = null;
if(header != null && header.startsWith("Bearer ")){
token = header.substring(7);
try {
userName = jwtUtil.extractUsername(token);
} catch (IllegalArgumentException e){
System.out.println("Unable to get JWT token.");
} catch (ExpiredJwtException e){
System.out.println("JWT Token has expired.");
} catch (SignatureException e){
System.out.println("Authentication Failed. Username or Password not valid.");
}
} else {
logger.warn("Couldn't find bearer string, will ignore the header");
}
if(userName != null && SecurityContextHolder.getContext().getAuthentication() == null){
UserDetails userDetails = userDetailsService.loadUserByUsername(userName);
if(jwtUtil.validateToken(token, userDetails)){
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
filterChain.doFilter(request, response);
}
}
请帮助我在这一点上,如果在情况下,我做任何不正确的
1条答案
按热度按时间7lrncoxx1#
通过更改UserEntity中UserDetails接口的三个覆盖方法的布尔值解决了该问题。
之前的值为false。将其更改为true后,该值生效!