spring securityで認証されたユーザーのidを取得したいのですがnullが返ってきます
spring securityで認証はできています。
認証後の偏移画面で
Authentication auth = SecurityContextHolder.getContext().getAuthentication(); //Principalからログインユーザの情報を取得 String userName = auth.getName();
にてログインユーザーの名前は取得できています。
さらにログインユーザーのidも取得したいです。
そのために「UserDetailsインターフェース」を実装したクラスを作成しidを取得しようとしています。
参考にしたサイトはこちら
該当コードを下記にまとめます。
Entity
@Entity @Table(name = "user") @Data public class LoginUser { @Column(name = "user_id") @Id private int userId; @Column(name = "user_name") private String userName; @Column(name = "password") private String password; }
UserDetailsインターフェースの実装コード
このコード内で「LoginUser」からidを取得する独自メソッドを設定しています。
public class UserDetailsImpl implements UserDetails { private static final long serialVersionUID = 1L; private LoginUser user; protected UserDetailsImpl() {}; public UserDetailsImpl(LoginUser user) { this.user=user; } public int getUserId() { return user.getUserId(); } @Override public Collection<? extends GrantedAuthority> getAuthorities() { // TODO 自動生成されたメソッド・スタブ return null; } @Override public String getPassword() { // TODO 自動生成されたメソッド・スタブ return null; } @Override public String getUsername() { // TODO 自動生成されたメソッド・スタブ return null; } @Override public boolean isAccountNonExpired() { // TODO 自動生成されたメソッド・スタブ return false; } @Override public boolean isAccountNonLocked() { // TODO 自動生成されたメソッド・スタブ return false; } @Override public boolean isCredentialsNonExpired() { // TODO 自動生成されたメソッド・スタブ return false; } @Override public boolean isEnabled() { // TODO 自動生成されたメソッド・スタブ return false; } }
controllerクラス内のメソッドに引数として「@AuthenticationPrincipal UserDetailsImpl userDetails」を設定しています。
そして「System.out.println(userDetails.getUserId());」でユーザーidを取得しようとしていますがnullが返ってきます。
@Controller public class HomeController { // インスタンスを作成しDIコンテナに格納。 @Autowired UserService userService; //userListのアドレスにアクセスした際にGetメソッドを実行。 @GetMapping("/userList") public String getUserList(Model model,@AuthenticationPrincipal UserDetailsImpl userDetails) { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); //Principalからログインユーザの情報を取得 String userName = auth.getName();//ユーザー名は取得できます。 System.out.println(userDetails.getUserId()); // userIdは nullが返ってきます。 //@Autowiredで作成したインスタンスを元に、userServiceのメソッドを呼び出す。 List<User> userList = userService.selectMany(); //userServiceから受け取ったデータをView側に渡す。 model.addAttribute("userList", userList); model.addAttribute("userName", userName); //template配下のファイル名を指定することでViewを呼び出せる。 return "userList"; } }
何が原因かわからず詰まっております。
何卒よろしくお願いいたします。
編集、追記依頼をいただきましたのでお言葉に甘えて追記しました。
UserDetailsインターフェースの実装コード内のisEnabledメソッドをtrueに変更しました。
public class UserDetailsImpl implements UserDetails { private static final long serialVersionUID = 1L; private LoginUser user; protected UserDetailsImpl() {}; public UserDetailsImpl(LoginUser user) { this.user=user; } public int getUserId() { return user.getUserId(); } @Override public Collection<? extends GrantedAuthority> getAuthorities() { // TODO 自動生成されたメソッド・スタブ return null; } @Override public String getPassword() { // TODO 自動生成されたメソッド・スタブ return null; } @Override public String getUsername() { // TODO 自動生成されたメソッド・スタブ return null; } @Override public boolean isAccountNonExpired() { // TODO 自動生成されたメソッド・スタブ return true; } @Override public boolean isAccountNonLocked() { // TODO 自動生成されたメソッド・スタブ return true; } @Override public boolean isCredentialsNonExpired() { // TODO 自動生成されたメソッド・スタブ return true; } @Override public boolean isEnabled() { // TODO 自動生成されたメソッド・スタブ return true; }
UserDetailsServiceインターフェースの実装クラス
@Service public class UserDetailsServiceImpl implements UserDetailsService{ @Autowired private LoginUserDao userDao; @Override public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { LoginUser user = userDao.findUser(userName); if (user == null) { throw new UsernameNotFoundException("User" + userName + "was not found in the database"); } List<GrantedAuthority> grantList = new ArrayList<GrantedAuthority>(); GrantedAuthority authority = new SimpleGrantedAuthority("USER"); grantList.add(authority); //rawDataのパスワードは渡すことができないので、暗号化 BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); //UserDetailsはインタフェースなのでUserクラスのコンストラクタで生成したユーザオブジェクトをキャスト UserDetails userDetails = (UserDetails)new User(user.getUserName(), encoder.encode(user.getPassword()),grantList); return userDetails; } }
セキュリティコンフィグレーションクラス
@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsServiceImpl userDetailsService; //フォームの値と比較するDBから取得したパスワードは暗号化されているのでフォームの値も暗号化するために利用 @Bean public BCryptPasswordEncoder passwordEncoder() { BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder(); return bCryptPasswordEncoder; } /** * 認可設定を無視するリクエストを設定 * 静的リソース(image,javascript,css)を認可処理の対象から除外する */ @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers( "/images/**", "/css/**", "/javascript/**" ); } /** * 認証・認可の情報を設定する * 画面遷移のURL・パラメータを取得するname属性の値を設定 * SpringSecurityのconfigureメソッドをオーバーライドしています。 */ @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/", "/home").permitAll() // アクセス制限のないURL .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") //ログインページはコントローラを経由しないのでViewNameとの紐付けが必要 .loginProcessingUrl("/sign_in") //フォームのSubmitURL、このURLへリクエストが送られると認証処理が実行される .usernameParameter("username") //リクエストパラメータのname属性を明示 .passwordParameter("password") .defaultSuccessUrl("/userList", true) //認証が成功した際に遷移するURL .failureUrl("/login?error") //認証が失敗した際に遷移するURL .permitAll() //どのユーザでも接続できる。 .and() .logout() .logoutUrl("/logout") .logoutSuccessUrl("/login?logout") .permitAll(); } @Autowired public void configure(AuthenticationManagerBuilder auth) throws Exception{ auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } }
mavenではなくてgradleを使用しています。
build gradle
dependencies { compile('org.springframework.boot:spring-boot-starter-data-jpa') implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'mysql:mysql-connector-java' annotationProcessor 'org.projectlombok:lombok' implementation 'org.springframework.boot:spring-boot-starter-security' // https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity5 compile group: 'org.thymeleaf.extras', name: 'thymeleaf-extras-springsecurity5', version: '3.0.4.RELEASE' // https://mvnrepository.com/artifact/javax.persistence/javax.persistence-api compile group: 'javax.persistence', name: 'javax.persistence-api', version: '2.2' testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' } }
他のコードも必要でしたら追記いたします。
回答1件
あなたの回答
tips
プレビュー