简体   繁体   English

如何在 Spring Security 中添加授权过滤器来验证令牌并设置安全上下文?

[英]How to add a authorization filter to validate token and set security context in spring security?

I have a spring MVC application using spring security 4 and I want to add authorization based on the jwt token in the request.我有一个使用 spring security 4 的 spring MVC 应用程序,我想根据请求中的 jwt 令牌添加授权。 what I need to do in the filter is to我需要在过滤器中做的是

  1. Take token from request header从请求头中获取令牌
  2. Send the token to external API and get the user details将令牌发送到外部 API 并获取用户详细信息
  3. Set the fetched details in the Security Context在安全上下文中设置获取的详细信息

But when I start the application, I get an error saying An AuthenticationManager is required .但是当我启动应用程序时,我收到一条错误消息,指出An AuthenticationManager is required I am not sure how the UserDetails service apply for my use case.我不确定 UserDetails 服务如何适用于我的用例。 Hence I have added a dummy return value for testing since without the UserDetailsService application is not working.因此,我添加了一个虚拟返回值进行测试,因为没有 UserDetailsS​​ervice 应用程序将无法工作。 Any idea on this?对此有什么想法吗?

Spring security config class Spring 安全配置类

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
  prePostEnabled = true
)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
@Qualifier("applicationUserService")
UserDetailsService userDetailsService;

@Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
  SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
  authenticationManagerBuilder
    .userDetailsService(userDetailsService)
    .passwordEncoder(bCryptPasswordEncoder());
}

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.csrf().disable().authorizeRequests()
    .antMatchers(HttpMethod.GET, "/home").hasAnyRole("ADMIN")
    .antMatchers(HttpMethod.GET, "/login").hasAnyRole("ADMIN")
    .anyRequest().authenticated()
    .and()
    .addFilter(new AuthorizationFilter(authenticationManager()))
    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}

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

Authorization Filter class授权过滤器类

public class AuthorizationFilter extends BasicAuthenticationFilter {

private static final Logger LOGGER = LoggerFactory.getLogger(AuthorizationFilter.class);

public AuthorizationFilter(AuthenticationManager authenticationManager) {
  super(authenticationManager);
}

@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
  LOGGER.info("Request Info : {}", req.getRequestURI());
  // get token
  // fetch details from external API
  // set security context
  List<GrantedAuthority> authorities = new ArrayList<>();
  authorities.add((GrantedAuthority) () -> "ROLE_ADMIN");
  SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("user1", null, authorities));
  LOGGER.info("security context principle:{}", SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
  LOGGER.info("authorities context:{}", SecurityContextHolder.getContext().getAuthentication().getAuthorities().toString());

  chain.doFilter(req, response);
}

UserDetailsService implementation UserDetailsS​​ervice 实现

@Service
@Qualifier("applicationUserService")
public class ApplicationUserServiceImpl implements UserDetailsService {

  @Override
  public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
    return new User("sidath", "123", emptyList());
  }
}

Try this steps试试这个步骤

  1. Define a AbstractAuthenticationProcessingFilter to evaluate request and return token.定义一个AbstractAuthenticationProcessingFilter来评估请求和返回令牌。

public class AwesomeFilter extends AbstractAuthenticationProcessingFilter {
    
    public AuthorizationFilter () {
       super(new AntPathRequestMatcher("/your_post_url", "POST"));
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
        
       // Evaluate request...
    
       // Build your custom authentication token with the info
       AwesomeToken token = new AwesomeToken();

       // Authenticate token with authentication manager
        return getAuthenticationManager().authenticate(token);
    }
  1. Define a AuthenticationProvider to supports your AwesomeToken .定义一个AuthenticationProvider来支持你的AwesomeToken Spring Security will try to "supports" this. Spring Security 将尝试“支持”这一点。
public class AwesomeProvider implements AuthenticationProvider {
    
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

      // Evaluate your custom token
      // Call your API, etc

      // Build your user authentication token details with authorities
         Collection<? extends GrantedAuthority> auths = Collections.singletonList(new 
                SimpleGrantedAuthority("ROLE_ADMIN"));
         AwesomeUserToken token = new AwesomeUserToken(auths);

      // Return user token
         return token;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return (AwesomeToken.class.isAssignableFrom(authentication));
    }
  1. Register classes in Spring Security Config.在 Spring Security Config 中注册类。
    @Override
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
           .authenticationProvider(new AwesomeProvider());
    }

    @Override
    public void addFilters(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception {

        AwesomeFilter filter = new AwesomeFilter();
        filter.setAuthenticationManager(authenticationManager);
        http
            .addFilterAfter(filter, UsernamePasswordAuthenticationFilter.class);
    }

Finally, when Spring Security detects the request with filter, it will try support with the provider and then return the token with the required authorities.最后,当 Spring Security 检测到带有过滤器的请求时,它将尝试支持提供者,然后返回具有所需权限的令牌。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM