Аутентификация Spring Security.getName возвращает null в контроллере

Это мой первый проект весной. Я пытаюсь получить имя пользователя, вошедшего в систему, но он возвращает null. Я также пробовал аннотацию AuthenticationPrincipal и другие способы, но она все равно возвращает null.

WebSecurityConfiguration класс:

@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter{

    @Autowired
    private UserDetailsService customUserDetailsService;

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

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .userDetailsService(customUserDetailsService)
            .passwordEncoder(encoder());
    }

    @Override
    protected void configure (HttpSecurity http) throws Exception {

        http
            .csrf().disable()
            .antMatcher("/**")
            .authorizeRequests()
                .antMatchers("/login**").permitAll()
                .anyRequest().authenticated();
    }

    public PasswordEncoder encoder() {
        return NoOpPasswordEncoder.getInstance();
    }
}

AuthorizationServerConfiguration класс:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private DataSource dataSource;

    @Autowired 
    private CustomUserDetailsService userDetailsService;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.checkTokenAccess("isAuthenticated()");
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

        clients.jdbc(dataSource);
    }

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

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

        endpoints.authenticationManager(authenticationManager)
            .tokenStore(tokenStore())
            .userDetailsService(userDetailsService)
            .approvalStoreDisabled();
    }

    @Bean 
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

}

ResourceServerConfiguration класс:

@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter{

    @Autowired
    TokenStore tokenStore;

    @Autowired
    DataSource dataSource;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId("scout").tokenStore(tokenStore);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {

        http
            .authorizeRequests()
                .antMatchers("/oauth/token", "/oauth/authorize **").permitAll();
        http
            .requestMatchers()
                .antMatchers("/api/patients/**")
                .and()
            .authorizeRequests()
                .antMatchers(HttpMethod.GET, "/api/patients/{\\d+}").access("hasAnyRole('PATIENT', 'DOCTOR')")
                .antMatchers("/api/patients/{\\d+}/medical-records").access("hasAnyRole ('PATIENT', 'DOCTOR')")
                .antMatchers("/api/patients/medical-records/{\\\\d+}/prescriptions").access("hasAnyRole('PATIENT', 'DOCTOR')")
                .antMatchers("/api/patients/**").access("hasRole('PATIENT')") 
                .and()
            .requestMatchers()
                .antMatchers("/api/doctors/**")
                .and()
            .authorizeRequests()
                .antMatchers("/api/doctors/**").access("hasRole('DOCTOR')"); 
    }
}

Ниже находится контроллер:

@GetMapping("/doctors")
public Doctor getDoctor(Authentication user) {
    System.out.println(user.getName());
    return doctorService.getDoctor(user.getName());
}

************************************Обновлять************* *******************

Я использую oauth2 для безопасности. Я пытаюсь получить имя пользователя, вошедшего в систему, в моем контроллере выше. Я попытался напечатать основной объект и получил org.springframework.security.oauth2.provider.OAuth2Authentication@24d14be1: Principal: com.prescribr.rest.service.CustomUserDetails@56d40b2f; Credentials: [PROTECTED]; Authenticated: true; Details: remoteAddress=0:0:0:0:0:0:0:1, sessionId=<SESSION>, tokenType=bearertokenValue=<TOKEN>; Granted Authorities: ROLE_DOCTOR

С другой стороны, Principle.getName() возвращает значение null.

Я использую токен доступа в своем заголовке при отправке запроса, как показано ниже, в почтальоне.

authorization: bearer theToken

Класс CustomUserDetails:

public class CustomUserDetails extends Users implements UserDetails {

    private static final long serialVersionUID = -8170449272852748515L;

    public CustomUserDetails(final Users user) {
        super(user);
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {

        return getRoles()
                .stream()
                .map(role -> new SimpleGrantedAuthority("ROLE_" + role.getRole()))
                .collect(Collectors.toList());
    }

    @Override
    public String getPassword() {
        // TODO Auto-generated method stub
        return super.getPassword();
    }

    @Override
    public String getUsername() {
        // TODO Auto-generated method stub
        return super.getEmail();
    }

    @Override
    public boolean isAccountNonExpired() {
        // TODO Auto-generated method stub
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        // TODO Auto-generated method stub
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        // TODO Auto-generated method stub
        return true;
    }

    @Override
    public boolean isEnabled() {
        // TODO Auto-generated method stub
        return true;
    }

}

Класс CustomUserDetailsService:

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private UsersRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {

        Optional<Users> usersOptional = userRepository.findByEmail(email);

        Users user = null;

        if (usersOptional.isPresent()) {
            System.out.println(usersOptional.isPresent());
            user = usersOptional.get();
        }else {
            throw new RuntimeException("Email is not registered!");
        }

        return new CustomUserDetails(user);
    }

}

Класс пользователей:

@Entity
@Table(name = "users")
public class Users {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name = "id")
    private int id; 

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "email")
    private String email;

    @Column(name = "password")
    private String password;

    @Column(name = "active")
    private int active;

    @OneToMany(cascade=CascadeType.ALL, 
               fetch=FetchType.EAGER
               )
    @JoinColumn(name = "user_id")
    private Set<Role> roles;

    public Users() {}

    public Users(Users user) {
        this.id = user.id;
        this.firstName = user.firstName;
        this.lastName = user.lastName;
        this.email = user.email;
        this.password = user.password;
        this.active = user.active;
        this.roles = user.roles;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getActive() {
        return active;
    }

    public void setActive(int active) {
        this.active = active;
    }

    public Set<Role> getRoles() {
        return roles;
    }

    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }

}

Еще раз спасибо!

Я думаю, что аннотация должна быть @AuthenticationPrincipal

AlexB 15.02.2019 12:40

Да, я пробовал. Я имел в виду @AuthenticationPrincipal, извините. Я пытался решить это с давних пор. Все еще возвращает ноль

rajjput sufiyaan 15.02.2019 14:40

Кажется, у вас две цепочки фильтров. Оба они захватывают /** URL-адреса. Один из них требует аутентификации, но не показывает, какой тип аутентификации следует использовать. Другой не защищает /doctor. Порядок вашей цепочки фильтров важен. Вот хороший ответ, чтобы понять несколько цепочек фильтров: stackoverflow.com/questions/54657163/…

Filip Hanik VMware 15.02.2019 20:29

Спасибо за ответ. Так должен ли я заказать сервер ресурсов на один и веб-безопасность на 2?

rajjput sufiyaan 15.02.2019 20:35

@rajjputsufiyaan: В вашем коде слишком много ошибок. Вы должны прочитать больше документации. Также вы должны сократить свой код до минимума, всего один метод контроллера, всего один URL. Если это работает, добавьте больше URL-адресов.

dur 16.02.2019 00:21

@rajjputsufiyaan Чтобы узнать о других проблемах в вашем коде, см. stackoverflow.com/questions/39429104/… и stackoverflow.com/questions/39457121/….

dur 16.02.2019 00:35

@FilipHanikPivotal Порядок цепочек правильный. AuthorizationServerConfiguration, ResourceServerConfiguration и последнее WebSecurityConfiguration . Последний является резервным и соответствует /** (а также логину для сервера авторизации).

dur 16.02.2019 00:43

самый простой: : @RequestMapping getDoctor(Princcipal user); (+1 и крупный план) .. см.: аргументы аннотации mvc

xerx593 16.02.2019 02:00

@dur спасибо, что поделились ссылками. Однако моя проблема не является дубликатом. Я попытался внедрить принципала и аутентификацию, а также использовал контекст безопасности в контроллере, но он все равно возвращает ноль.

rajjput sufiyaan 16.02.2019 05:14

@ xerrx593 Я пытался использовать Principal, он возвращает null

rajjput sufiyaan 16.02.2019 05:16

@rajjputsufiyaan Если Principal означает null или Authentication в контексте, это означает, что вы не вошли в систему. Вы анонимны. Так что вам нужно описать, что вы делаете шаг за шагом. По крайней мере, вы должны показать свой запрос с заголовками для URL-адреса вашего контроллера.

dur 16.02.2019 09:48

@rajjputsufiyaan Я думаю, все мы, пытающиеся помочь вам, думали, что вы получаете null за объект Principal или Authentication. Ваше редактирование проясняет. Только метод getName() возвращает null.

dur 16.02.2019 10:37

@rajjputsufiyaan Вы используете пользовательский объект UserDetails, покажите код. Может вы не так заполняете?

dur 16.02.2019 10:43

@dur Извините, если мой исходный пост был непонятен. Я добавил классы в свой вопрос выше.

rajjput sufiyaan 16.02.2019 11:05

@rajjputsufiyaan Не могли бы вы попробовать перевести Principal на CustomUserDetails и вызвать getUsername() вместо getName()?

dur 16.02.2019 12:19

@dur Я пытался указать принципала, который вводится в контроллер, как: Пользователь CustomUserDetails = (CustomUserDetails) принципал; и я получил сообщение об ошибке, что OauthAuthentication не может быть приведен к CustomUserDetails, и я также попробовал (CustomUserDetails) SecurityContextHolder.getContext().getAuthentication().getPr‌​incipal(), который снова дал мне значение null для user.getUsername()

rajjput sufiyaan 16.02.2019 12:27
1
16
1 040
0

Другие вопросы по теме