Получение исключения весенней безопасности Учетная запись пользователя заблокирована \ - PullRequest
0 голосов
/ 12 февраля 2019

Мы реализовали Spring Security в нашем проекте угловой загрузочной пружины.Здесь мы получаем исключение Spring Security Учетная запись пользователя заблокирована

Пожалуйста, просмотрите следующий код.

SecurityConfiguration.java

package com.jwt.security;

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.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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.csrf.CsrfFilter;

import com.jwt.security.filter.AuthenticationTokenFilter;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration<jwtAuthenticationEntryPoint>  extends WebSecurityConfigurerAdapter{

    @Autowired private UserDetailsService userDetailsService;

    @Autowired private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint ; 

    @Autowired
    public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder.userDetailsService(this.userDetailsService).passwordEncoder( PasswordEncoder());

    }

    @Bean
    public PasswordEncoder PasswordEncoder() {  
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean 
    public AuthenticationTokenFilter authenticationTokenFilterBean( ) {
        return new AuthenticationTokenFilter(); 
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception    {
        httpSecurity.csrf().disable()
        .exceptionHandling()
        .authenticationEntryPoint(jwtAuthenticationEntryPoint).and()
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
        .authorizeRequests()
        .antMatchers("/**").permitAll()
        .antMatchers("/registration").permitAll()
        .antMatchers("/login").permitAll()
        .antMatchers(HttpMethod.OPTIONS ,"/**").permitAll()
        .anyRequest().authenticated();
        httpSecurity.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class)
        .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class);
        httpSecurity.headers().cacheControl();
        httpSecurity.headers().httpStrictTransportSecurity().includeSubDomains(true).maxAgeInSeconds(31536000);       
    }
}

фильтр токенов аутентификации AuthenticationTokenFilter.hjava

package com.jwt.security.filter;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import com.jwt.security.JwtTokenUtil;

public class AuthenticationTokenFilter extends OncePerRequestFilter {

    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Value("${jwt.header}")
    private String tokenHeader;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        String authToken = request.getHeader(this.tokenHeader);
        if (authToken != null && authToken.length() > 7) {
            authToken = authToken.substring(7);
        }
        String username = jwtTokenUtil.getUsernameFromToken(authToken);
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
            boolean isValid = jwtTokenUtil.validateToken(authToken, userDetails);
            if (isValid) {
                UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            }
        }
        filterChain.doFilter(request, response);
    }
}

Здесь я получаю null для authToken при запуске из почтальона

Код для JwtUtil выглядит следующим образом

package com.jwt.security;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

@Component
public class JwtTokenUtil implements Serializable {

    static final String CLAIM_KEY_USERNAME = "sub";
    static final String CLAIM_KEY_AUDIENCE = "audience";
    static final String CLAIM_KEY_CREATED = "created";

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.expiration}")
    private Long expiration;

    public String getUsernameFromToken(String authToken) {
        String username = null;
        try {
            final Claims claims = getClaimsFromToken(authToken);
            username = claims.getSubject();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            username = null;
        }
        return username;
    }

    private Claims getClaimsFromToken(String authToken) {
        // TODO Auto-generated method stub
        Claims claims = null;
        try {
            claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(authToken).getBody();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            claims = null;
        }

        return claims;
    }

    public boolean validateToken(String authToken, UserDetails userDetails) {
        // TODO Auto-generated method stub
        JwtUser user = (JwtUser) userDetails;
        final String username = getUsernameFromToken(authToken);
        return (username.equals(user.getUsername()) && !isTokenExpired(authToken));

    }

    private boolean isTokenExpired(String authToken) {
        final Date expiration = getExpirationDateFromToken(authToken);
        return expiration.before(new Date());
    }

    private Date getExpirationDateFromToken(String authToken) {
        // TODO Auto-generated method stub
        Date expiration = null;
        final Claims claims = getClaimsFromToken(authToken);
        if (claims != null) {
            expiration = claims.getExpiration();
        } else {
            expiration = null;
        }
        return expiration;
    }
    public String generateToken(JwtUser userDetails) {
        Map<String,Object> claims = new HashMap<String,Object>();
        claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
        claims.put(CLAIM_KEY_CREATED, new Date());
        return generateToken(claims);

    }

    public String generateToken(Map<String , Object> claims ) {
        return Jwts.builder().setClaims(claims).setExpiration(generateExpirationDate()).signWith(SignatureAlgorithm.HS512, secret).compact();
    }

    private Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + expiration * 1000);
    }
}

Код для CsrfHeaderFilter выглядит следующим образом

package com.jwt.security;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.WebUtils;

public class CsrfHeaderFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        System.out.println("...CsrfToken.class.getName() :::" + CsrfToken.class.getName()); 
//      CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
    //  CsrfToken csrfToken = new HttpSessionCsrfTokenRepository().loadToken(request);
        CsrfToken csrfToken = (CsrfToken) request.getAttribute("_csrf");
        String token = null;
        Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
        if(csrfToken != null) {
        token = csrfToken.getToken();
        }
        if (cookie == null || token != null && !token.equals(cookie.getValue())) {
            cookie = new Cookie("XSRF-TOKEN", token);
            cookie.setPath("/");
            response.addCookie(cookie);

        }
        filterChain.doFilter(request, response);
    }

}

Используется контроллер AuthenticationController. Код выглядит следующим образом:

package com.jwt.security.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.jwt.security.JwtTokenUtil;
import com.jwt.security.JwtUser;
import com.jwt.security.domain.User;
import com.jwt.security.domain.UserDTO;
import com.jwt.security.exception.UnauthorizedException;

@RestController
public class AuthenticationController {

    @Value("${jwt.header}")
    private String tokenHeader;

    @Autowired private AuthenticationManager authenticationManager; 
    @Autowired private JwtTokenUtil jwtTokenUtil;

    @PostMapping(value="/login")
    public ResponseEntity<UserDTO> login(@RequestBody User user, HttpServletRequest request , HttpServletResponse response) {
    try {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        System.out.println("matches ::" + encoder.matches("123", user.getPassword()));
        Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getEmail(), user.getPassword()));
        final JwtUser userDetails = (JwtUser)authentication.getPrincipal();
        SecurityContextHolder.getContext().setAuthentication(authentication);
        final String token = jwtTokenUtil.generateToken(userDetails);
        response.setHeader("Token", token);
        return new ResponseEntity<UserDTO>(new UserDTO(userDetails.getUser(), token) , HttpStatus.OK);
    }catch(UnauthorizedException ex) {
        ex.printStackTrace();
        throw new UnauthorizedException(ex.getMessage());
    }
    }


}

При вызове http://localhost:8080/login от почтальона и передаче правильного адреса электронной почты и пароля, мы получаем следующее исключение

org.springframework.security.authentication.LockedException: User account is locked

Пожалуйста, совет

1 Ответ

0 голосов
/ 12 февраля 2019

В сообщении написано "Учетная запись пользователя заблокирована".Это происходит после ряда неудачных событий аутентификации.В конечном итоге учетная запись разблокируется в зависимости от реализации.

В Spring Security есть только два места:

  1. AccountStatusUserDetailsChecker.check(UserDetails user)
public void check(UserDetails user) {
    if (!user.isAccountNonLocked()) {
        throw new LockedException(messages.getMessage(
                "AccountStatusUserDetailsChecker.locked", "User account is locked"));
    }

    if (!user.isEnabled()) {
        throw new DisabledException(messages.getMessage(
                "AccountStatusUserDetailsChecker.disabled", "User is disabled"));
    }

    if (!user.isAccountNonExpired()) {
        throw new AccountExpiredException(
                messages.getMessage("AccountStatusUserDetailsChecker.expired",
                        "User account has expired"));
    }

    if (!user.isCredentialsNonExpired()) {
        throw new CredentialsExpiredException(messages.getMessage(
                "AccountStatusUserDetailsChecker.credentialsExpired",
                "User credentials have expired"));
    }
}
AbstractUserDetailsAuthenticationProvider.DefaultPreAuthenticationChecks.check(UserDetails user)

Так что, если вы хотите установить точку останова, вот с чего вы начнете.

Все это происходит в вашем UserDetailsServiceкоторый есть в вашей конфигурации.

    @Autowired private UserDetailsService userDetailsService;

Этот сервис возвращает объект, который реализует интерфейс UserDetails

    public interface UserDetails {
        boolean isAccountNonLocked();
    }

, если этот метод возвращает false, учетная запись заблокирована.название немного сбивает с толку.

Поскольку мы не знаем, каков ваш UserDetailsService, мы не можем сказать вам, как это заполняется.Поэтому рекомендуется просто установить точку останова при возникновении ошибки.

Если вы не хотите, чтобы функция блокировки учетной записи была включена, есть разные способы реализовать это.Если вы переопределяете бин UserDetailsService, вы всегда можете вернуть пользователей, которые никогда не блокируются.

Другой способ - ввести свой собственный контролер

   DaoAuthenticationProvider daoProvider = .... 
   daoProvider.setPreAuthenticationChecks(toCheck -> {});

Существует также PostAuthenticationChecks объект, чтобы увидеть, если ваш пароль истек.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...