Это мой первый проект весной. Я пытаюсь получить имя пользователя, вошедшего в систему, но он возвращает 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, извините. Я пытался решить это с давних пор. Все еще возвращает ноль
Кажется, у вас две цепочки фильтров. Оба они захватывают /** URL-адреса. Один из них требует аутентификации, но не показывает, какой тип аутентификации следует использовать. Другой не защищает /doctor. Порядок вашей цепочки фильтров важен. Вот хороший ответ, чтобы понять несколько цепочек фильтров: stackoverflow.com/questions/54657163/…
Спасибо за ответ. Так должен ли я заказать сервер ресурсов на один и веб-безопасность на 2?
@rajjputsufiyaan: В вашем коде слишком много ошибок. Вы должны прочитать больше документации. Также вы должны сократить свой код до минимума, всего один метод контроллера, всего один URL. Если это работает, добавьте больше URL-адресов.
@rajjputsufiyaan Чтобы узнать о других проблемах в вашем коде, см. stackoverflow.com/questions/39429104/… и stackoverflow.com/questions/39457121/….
@FilipHanikPivotal Порядок цепочек правильный. AuthorizationServerConfiguration, ResourceServerConfiguration и последнее WebSecurityConfiguration . Последний является резервным и соответствует /** (а также логину для сервера авторизации).
самый простой: : @RequestMapping getDoctor(Princcipal user); (+1 и крупный план) .. см.: аргументы аннотации mvc
@dur спасибо, что поделились ссылками. Однако моя проблема не является дубликатом. Я попытался внедрить принципала и аутентификацию, а также использовал контекст безопасности в контроллере, но он все равно возвращает ноль.
@ xerrx593 Я пытался использовать Principal, он возвращает null
@rajjputsufiyaan Если Principal означает null или Authentication в контексте, это означает, что вы не вошли в систему. Вы анонимны. Так что вам нужно описать, что вы делаете шаг за шагом. По крайней мере, вы должны показать свой запрос с заголовками для URL-адреса вашего контроллера.
@rajjputsufiyaan Я думаю, все мы, пытающиеся помочь вам, думали, что вы получаете null за объект Principal или Authentication. Ваше редактирование проясняет. Только метод getName() возвращает null.
@rajjputsufiyaan Вы используете пользовательский объект UserDetails, покажите код. Может вы не так заполняете?
@dur Извините, если мой исходный пост был непонятен. Я добавил классы в свой вопрос выше.
@rajjputsufiyaan Не могли бы вы попробовать перевести Principal на CustomUserDetails и вызвать getUsername() вместо getName()?
@dur Я пытался указать принципала, который вводится в контроллер, как: Пользователь CustomUserDetails = (CustomUserDetails) принципал; и я получил сообщение об ошибке, что OauthAuthentication не может быть приведен к CustomUserDetails, и я также попробовал (CustomUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal(), который снова дал мне значение null для user.getUsername()
Я думаю, что аннотация должна быть
@AuthenticationPrincipal