永远不会调用自定义用户详细信息和自定义身份验

时间:2017-02-26 09:33:06

标签: spring spring-boot spring-security

我需要在经过身份验证的用户的用户详细信息中添加一些其他数据。所以我写了一个自定义详细信息服务,并作为第二种方法自定义身份验证提供程序,以丰富用户对象中的数据。但是安全上下文中的主要对象保持字符串而不是成为所需的用户对象,当我设置断点时,我的自定义详细信息服务和身份验证提供者看起来这个代码永远不会被春天使用,尽管我的自定义类列在Springs认证经理建设者。

这是我的自定义用户详细信息服务:

package edu.kit.tm.cm.bamsg.bffweb.iamservice;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import java.util.HashSet;
import java.util.Set;

/*** @author schlund*/

public class CustomStudentDetailsService implements UserDetailsService {

    private SecurityUserRepository securityUserRepository;

    public CustomStudentDetailsService(SecurityUserRepository userSecurityRepository){
        this.securityUserRepository=userSecurityRepository;
    }


    @Override
    public SecurityUser loadUserByUsername(String kitID) throws UsernameNotFoundException {

        try {
            SecurityUser securityPerson = securityUserRepository.findByUsername(kitID);
            if (securityPerson == null) {
                return null;
            }
            return securityPerson;
        }
        catch (Exception e){
        throw new UsernameNotFoundException("User not found");
        }
    }

    private Set<GrantedAuthority> getAuthorities(SecurityUser securityPerson){
        Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
        GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(securityPerson.getRole());
        authorities.add(grantedAuthority);
        return authorities;
    }

}

这是我的自定义身份验证提供程序:

package edu.kit.tm.cm.bamsg.bffweb.iamservice;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    public Authentication authenticate(Authentication authentication ) throws AuthenticationException {
        String password = authentication.getCredentials().toString().trim();
        SecurityUser appUser = new SecurityUser();
        return new UsernamePasswordAuthenticationToken(appUser, password, null);
  }
  @Override
  public boolean supports(Class<? extends Object> authentication) {
      return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
  }

} 

这是我的网络安全配置:

package edu.kit.tm.cm.bamsg.bffweb;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.cloud.security.oauth2.client.feign.OAuth2FeignRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;

import edu.kit.tm.cm.bamsg.bffweb.iamservice.*;

@Configuration
@EnableOAuth2Sso
@EnableGlobalMethodSecurity(prePostEnabled = true)
@ComponentScan("edu.kit.tm.cm.bamsg.bffweb.iamservice")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private static final String REALM = "bam";

    @Autowired
    private CustomAuthenticationProvider authProvider; 

    @Autowired
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
      auth.authenticationProvider(authProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
      http
            .logout()
            .and()
            //endpoints without authentication
            .authorizeRequests().antMatchers("/logged", "/userData").permitAll()
            .and()
            // default with authentication
            .authorizeRequests().anyRequest().authenticated()
            .and()
            .csrf()
            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}

    @Bean
    public OAuth2FeignRequestInterceptor oAuth2FeignRequestInterceptor(OAuth2ClientContext context, OAuth2ProtectedResourceDetails details) {
        return new OAuth2FeignRequestInterceptor(context, details);
    }

    @Bean
    BasicAuthenticationEntryPoint getBasicAuthEntryPoint() {
        BasicAuthenticationEntryPoint basicAuth = new BasicAuthenticationEntryPoint();
        basicAuth.setRealmName(REALM);
        return basicAuth;
    }
}

至少在使用System.out.println在代码行进行身份验证之后,应该已经调用了自定义服务,但不幸的是,它们不是。从未到过自定义服务中的断点,并且主体仍然是字符串而不是我的自定义用户:

@ComponentScan("edu.kit.tm.cm.bamsg.bffweb.iamservice")
@RestController
@RequestMapping("/api/theses")
public class ThesisController {

    @Autowired
    private ThesisClient thesisClient;

    @Autowired
    private ThesisPersonLinker linker;

    @Autowired
    private ThesisPersonFilter filter;

    @GetMapping
    @PreAuthorize("hasRole('theses')")
    public ResponseEntity<Collection<ThesisFrontendDTO>> findAllTheses() {
       System.out.println(SecurityContextHolder.getContext().getAuthentication().getPrincipal());

扩展用户类看起来像这样:

package edu.kit.tm.cm.bamsg.bffweb.iamservice;

import org.springframework.security.core.userdetails.User;


public class SecurityUser extends User{

    String firstName;
    String name;
    String password;

    private static final long serialVersionUID = 1L;

    public SecurityUser() {
        super("user", "none", null);
        firstName = "Rainer";
        name = "Schlund";
        password = "meins";
    }

    public String getRole(){
        return "Student";
    }


}

代码包含一些用于测试的简化,例如SecurityPerson总是返回同一个人,但我认为这应该不是问题。

2 个答案:

答案 0 :(得分:1)

要解决“安全性上下文中的主要对象保留字符串而不成为所需的用户对象”的问题,如果您遍历了Principal对象,则可以使用getCreditantial()方法仅返回对象(考虑到安全性用户是主要对象)它没有提供足够的信息来成为正确的主要对象。

请查看UserDetailsPrincipal类以实现主体实现:

public class UserDetailsPrincipal extends org.springframework.security.core.userdetails.User implements UserDetails {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private Member user;
    List<GrantedAuthority> authorities;
    
    public UserDetailsPrincipal(Member user, List<GrantedAuthority> authorities ) {
        super(user.getLogin(),user.getEncrytedPassword(),authorities);
        this.authorities = authorities;
        this.user = user;
    }
    
//  @Override
//  public Collection<? extends GrantedAuthority> getAuthorities() { 
//      return this.authorities;
//  }

    @Override
    public String getPassword() {
        return user.getEncrytedPassword();
    }

    @Override
    public String getUsername() {
        return user.getLogin();
    }

    @Override
    public boolean isAccountNonExpired() {
        return !user.getIsExpired();
    }

    @Override
    public boolean isAccountNonLocked() {
        return !user.getIsLocked() || user.getIsLocked() == null;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return !user.getIsExpired() || user.getIsExpired() == null;
    }

    @Override
    public boolean isEnabled() {
        return user.getActive() == 1;
    }

}
  1. 还使用了如下的customAuthProvider:

    @ Slf4j @Component(“ customAuthProvider”) @Transactional(readOnly = true,propagation = Propagation.REQUIRES_NEW) 公共类CustomAuthenticationProvider实现AuthenticationProvider {

     @Autowired
     @Qualifier("userDetailsServiceAdapter")
     private UserDetailsServiceAdapter userDetailsService;
    
     @Override
     public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    
         String login = authentication.getName();
         String password = authentication.getCredentials().toString();
    
         /* Member member = userRepository.findUserAccount(login); */
         log.info("user for login inside custom auth service service  : " + login);
         if (!StringUtils.isEmpty(login) && !StringUtils.isEmpty(password)) {
             try {
                 UserDetails userDetail = userDetailsService.loadUserByUsernameAndPassword(login, password);
                 UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(userDetail,
                         userDetail.getPassword(), userDetail.getAuthorities());
    
                 token.setDetails(userDetail);
                 return token;
             } catch (UsernameNotFoundException exception) {
                 return new UsernamePasswordAuthenticationToken(login, password, new ArrayList<>());
             }
         } else {
             return new UsernamePasswordAuthenticationToken(login, password, new ArrayList<>());
         }
     }
    
     @Override
     public boolean supports(Class<?> authentication) {
         return authentication.equals(UsernamePasswordAuthenticationToken.class);
     }
    

    }

答案 1 :(得分:0)

如果您希望Spring安全性使用您的身份验证提供程序,则需要提供一些提供身份验证凭据的入口点。以下是WebSecuritConfig类的示例:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@ComponentScan
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private static final String REALM = "realm";

    @Autowired
    private CustomAuthenticationProvider authProvider; 

    @Autowired
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .logout()
            .and()
            // default with authentication
            .authorizeRequests().anyRequest().authenticated()
            .and()
            .csrf()
            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
            .and().httpBasic().realmName(REALM).authenticationEntryPoint(getBasicAuthEntryPoint());
    }

    @Bean
    BasicAuthenticationEntryPoint getBasicAuthEntryPoint() {
        BasicAuthenticationEntryPoint basicAuth = new BasicAuthenticationEntryPoint();
        basicAuth.setRealmName(REALM);
        return basicAuth;
    }

}

您需要更改SecurityUser构造函数,因为您无法将null权限传递给超级构造函数:

public SecurityUser() {
        super("user", "none", new ArrayList<>());
        firstName = "Rainer";
        name = "Schlund";
        password = "meins";
}

提供身份验证提供程序时,不使用UserDetailsS​​ervice。所以你需要在auth提供程序中使用它。