質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.34%

(Spring Security)ログイン認証時のカラム名(username, password)を任意のカラム名に変更する方法

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 3,909

_cocapeach

score 19

お世話になります。

Spring BootとSpring Securityを使用して、ログイン認証を実装しています。
デフォルトでは、DBにusernameとpasswordのカラムを持っていないといけないと思うのですが、
usernameをlogin_idというカラムで持ちたいと思っています。

実装方法を調べたのですが、ログイン認証の実装方法が自分と違っていたので、
参考にはなりませんでした。

ご教示頂けますと幸いです。

フォルダ階層

現時点のデフォルトのまま実装しているソースコードを記載致します。

//LoginController.java
package com.sample;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class LoginController
{
    public static final String PAGE = "/login";
    private static final String HTML = "login";

    @RequestMapping(value = LoginController.PAGE)
    public String top(Model model)
    {
        return LoginController.HTML;
    }
}
//TopController.java
package com.sample;

import java.security.Principal;

import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class TopController
{
    public static final String PAGE = "/";
    private static final String HTML = "top";

    @RequestMapping(value = TopController.PAGE, method = RequestMethod.GET)
    public String top(Principal principal, Model model)
    {
            Authentication authentication = (Authentication) principal;
        MemberEntity user = (MemberEntity) authentication.getPrincipal();
        model.addAttribute("user", user);
        return TopController.HTML;
    }
}
//MemberEntity.java
package com.sample;

import java.util.Collection;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

@Entity
@Table(name = "member")
public class MemberEntity implements UserDetails
{
    private static final long serialVersionUID = 1667698003975566301L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(nullable = false, unique = true)
    private String username;

    @Column(nullable = false)
    private String password;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities()
    {
        return null;
    }

    @Override
    public String getPassword()
    {
        return this.password;
    }

    @Override
    public String getUsername()
    {
        return this.username;
    }

    @Override
    public boolean isAccountNonExpired()
    {
        return true;
    }

    @Override
    public boolean isAccountNonLocked()
    {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired()
    {
        return true;
    }

    @Override
    public boolean isEnabled()
    {
        return true;
    }
}
//MemberRepository.java
package com.sample;

import org.springframework.data.jpa.repository.JpaRepository;

public interface MemberRepository extends JpaRepository<MemberEntity, Long>
{
    public MemberEntity findByUsername(String username);
}
//MemberServiseImpl.java

package com.sample;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Service
public class MemberServiceImpl implements UserDetailsService
{
    private MemberRepository memberRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
    {
        if (StringUtils.isEmpty(username))
        {
            throw new UsernameNotFoundException("");
        }

        MemberEntity memberEntity = memberRepository.findByUsername(username);
        if (memberEntity == null)
        {
            throw new UsernameNotFoundException("");
        }

        return memberEntity;
    }

    @Autowired
    public void setMemberRepository(MemberRepository memberRepository)
    {
        this.memberRepository = memberRepository;
    }
}
//WebSecurityConfig.java
package com.sample;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception
    {
        httpSecurity.authorizeRequests().anyRequest().authenticated();
        httpSecurity.formLogin().loginPage(LoginController.PAGE).usernameParameter("user")
                .passwordParameter("pass").permitAll();
        httpSecurity.logout()
        .logoutRequestMatcher(new AntPathRequestMatcher("/logout**"))       // ログアウト処理のパス
        .logoutSuccessUrl("/login");
    }

    @Override
    protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder)
            throws Exception
    {
        authenticationManagerBuilder.userDetailsService(this.userDetailsService)
        .passwordEncoder(NoOpPasswordEncoder.getInstance());;
    }

    @Autowired
    public void setUserDetailsService(UserDetailsService userDetailsService)
    {
        this.userDetailsService = userDetailsService;
    }
}
//Login.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>ログイン</title>
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
</head>
<body>
  <form action="" th:action="@{/login}" method="post">
    <p>
      ユーザーID:
      <input type="text" name="user" />
    </p>
    <p>
      パスワード:
      <input type="password" name="pass" />
    </p>
    <p>
      <input type="submit" value="ログイン" />
    </p>
  </form>
  <div th:if="${session['SPRING_SECURITY_LAST_EXCEPTION']} != null">
    <span th:text="${session['SPRING_SECURITY_LAST_EXCEPTION'].message}"></span>
  </div>
</body>
</html>


以上となります。宜しくお願い申し上げます。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • asahina1979

    2018/02/22 19:31

    丸パクリできるソースは基本ないです

    キャンセル

  • asahina1979

    2018/02/22 19:59

    変えたい場所をすでにあなたは変更してますが何がわからないんでしょうか?

    キャンセル

  • _cocapeach

    2018/02/22 20:04

    asahina1979様 usernameではなくlogin_idというカラム名で認証を行いたいのですが、すでに変更してあるというのはどの箇所でしょうか?

    キャンセル

回答 3

checkベストアンサー

0

Spring Bootだと定義系(xml)などを必要としないようになっているため余りデフォルトのものを変える事はしない方がいいですね。とりあえず、AuthenticationManagerBuilder.jdbcAuthenticationを使用すればSQLで指定できそうなのでその方法を記述します。※.別途ロール用のテーブルが必要になります。

・application.propertiesにユーザを検索するSQLを定義する

[application.properties]
spring.datasource.url=jdbc:mysql://IPアドレス/DB名
spring.datasource.username=ユーザ名
spring.datasource.password=パスワード
spring.datasource.driverClassName=com.mysql.jdbc.Driver

spring.queries.users-query=select login_id as username, password, true as enabled from テーブル名 where login_id=?

・WebSecurityConfig.javaの内容を以下のようにする

[WebSecurityConfig.java]

// パッケージ省略

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private DataSource dataSource;

    @Value("${spring.queries.users-query}")
    private String usersQuery;

    @Override
    protected void configure(AuthenticationManagerBuilder auth)
            throws Exception {

        auth.jdbcAuthentication()
                .usersByUsernameQuery(usersQuery)
                .authoritiesByUsernameQuery("select login_id as username, authority from authorities where login_id = ?")
                .dataSource(dataSource);
    }
}


autoritiesByUsernameQueryメソッドで指定しているSQLもuserByUsernameQueryメソッドで指定しているようにapplication.propertiesに定義したSQLを指定可能。(直書きも出来るという例)

autoritiesByUsernameQueryで指定しているようなROLE用のテーブルが必要になるので作成してください。authorityカラムには"ROLE_USER"とか入ります。

私が検証用に作成したテーブル
テーブル名:authorities
カラム1:login_id varchar(20) Not NULL
カラム2:authority varchar(20) Not NULL
主キーはlogin_id
login_idはmemberテーブルのlogin_idと同じ値
authorityは'USER_ROLE'とか'ADMIN_ROLE'とか入れます。(使用用途は不明)
※.ROLEに関してはSpring Securityの資料を探ってください。

MemberEntity.java/MemberRepository.java/MemberServiceImpl.javaは不要となります。

まぁ、こんなこともできるということで試してみてください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/02/23 15:51

    お手数をお掛けいたしました。
    色々とご教示頂き、誠に有難うございました。

    キャンセル

  • 2018/02/23 17:52

    まあ本当は repositoryインタフェースに findBy からはじまる PHPでいうところのマジックメソッド方式でいいんだけどね。

    findBy + entityのフィールド名 + [[ And + entityのフィールド名 ] And + entityのフィールド名 ](対応する引数)

    の形式

    キャンセル

  • 2018/02/23 17:54

    なるほどそういうやり方もありますか。

    キャンセル

0

質問への追記・修正の依頼でのやりとりから...
6.3. 認証
上記URLのページで「ユーザ情報取得クエリ」の箇所で書かれているとおりSQLを修正することで対応できると思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/02/23 15:10

    unz.hori 様 ご教示頂けますと幸いですが、かなりご面倒をかけてしまいそうなので、unz.hori様にお任せ致します。

    キャンセル

  • 2018/02/23 15:11

    じゃあ、別途回答に書きます。

    キャンセル

  • 2018/02/23 15:23

    恐れ入ります。宜しくお願い致します。

    キャンセル

0

asahina1979さんのコメントを元に...

元々の構成で

・MemberEntity.javaの変更点
usernameの代わりにloginIdを定義(getterも)

・MemberRepository.javaの変更点
public MemberEntity findByUsername(String username); → public MemberEntity findByLoginId(String username);

でいけるみたいです。こっちの方が楽っすねw。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.34%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る