2

解決方法がわからない設計上の問題があります。Spring 3.2.4 と Spring security 3.1.4 を使用しています。

私のデータベースには、次のような Account テーブルがあります。

create table Account (id identity,
                        username varchar unique,
                        password varchar not null,
                        firstName varchar not null, 
                        lastName varchar not null,
                        university varchar not null,
                        primary key (id));

最近まで、私のユーザー名は単なるユーザー名でしたが、多くのユーザーが代わりに電子メール アドレスでログインしたいため、代わりに電子メール アドレスに変更しました。

次のようなユーザープロファイルへのリンクを取得したすべてのページに含めるヘッダーがあります。

<a href="/project/users/<%= request.getUserPrincipal().getName()%>" class="navbar-link"><strong><%= request.getUserPrincipal().getName()%></strong></a>

問題は、<%= request.getUserPrincipal().getName()%>今すぐメールを返すことです。ユーザーのメールをリンクしたくありません。代わりに、すべてのユーザーがプロファイルにリンクする必要がある ID を使用したいと考えています。

すべてのページからユーザー ID にアクセスするにはどうすればよいですか?

私は2つの解決策を考えてきましたが、よくわかりません:

  1. ID も含めるようにプリンシパルを変更します。これを行う方法がわからず、トピックに関する適切な情報を見つけるのに問題があります。
  2. ユーザー全体を含むすべてのコントローラーにモデル属性を追加しますが、これはこのように本当に醜いでしょう。

Account account = entityManager.find(Account.class, email);
model.addAttribute("account", account);

より多くの方法もあり、どれを優先するかはわかりません。

十分に明確であることを願っています。これについて何か助けてくれてありがとう。

====== 答えに従って編集 =======

Account を編集して UserDetails を実装すると、次のようになります (自動生成されたものは後で修正します)。

@Entity
@Table(name="Account")
public class Account implements UserDetails {

    @Id
    private int id;

    private String username;

    private String password;

    private String firstName;

    private String lastName;

    @ManyToOne
    private University university;

    public Account() {

    }

    public Account(String username, String password, String firstName, String lastName, University university) {
        this.username = username;
        this.password = password;
        this.firstName = firstName;
        this.lastName = lastName;
        this.university = university;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setUsername(String username) {
        this.username = username;
    }

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

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

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

    public University getUniversity() {
        return university;
    }

    public void setUniversity(University university) {
        this.university = university;
    }

    public int getId() {
        return id;
    }

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

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        // TODO Auto-generated method stub
        return null;
    }

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

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

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

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

私も追加しました

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

私のjspファイルに、IDに到達しようとしています

<sec:authentication property="principal.id" />

これにより、次のことがわかります

org.springframework.beans.NotReadablePropertyException: Invalid property 'principal.id' of bean class [org.springframework.security.authentication.UsernamePasswordAuthenticationToken]: Bean property 'principal.id' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?

======答えに従って2を編集=======

春のソーシャル サンプルに基づいてアプリケーションを作成しましたが、今まで何も変更する必要はありませんでした。

これは関連があると思われるファイルです。これ以外に必要なものがあれば教えてください。

AccountRepository.java

public interface AccountRepository {

    void createAccount(Account account) throws UsernameAlreadyInUseException;

    Account findAccountByUsername(String username);

}

JdbcAccountRepository.java

@Repository
public class JdbcAccountRepository implements AccountRepository {

    private final JdbcTemplate jdbcTemplate;

    private final PasswordEncoder passwordEncoder;

    @Inject
    public JdbcAccountRepository(JdbcTemplate jdbcTemplate, PasswordEncoder passwordEncoder) {
        this.jdbcTemplate = jdbcTemplate;
        this.passwordEncoder = passwordEncoder;
    }

    @Transactional
    public void createAccount(Account user) throws UsernameAlreadyInUseException {
        try {
            jdbcTemplate.update(
                    "insert into Account (firstName, lastName, username, university, password) values (?, ?, ?, ?, ?)",
                    user.getFirstName(), user.getLastName(), user.getUsername(), user.getUniversity(),
                    passwordEncoder.encode(user.getPassword()));
        } catch (DuplicateKeyException e) {
            throw new UsernameAlreadyInUseException(user.getUsername());
        }
    }

    public Account findAccountByUsername(String username) {
        return jdbcTemplate.queryForObject("select username, firstName, lastName, university from Account where username = ?",
                new RowMapper<Account>() {
                    public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
                        return new Account(rs.getString("username"), null, rs.getString("firstName"), rs.getString("lastName"), new University("test"));
                    }
                }, username);
    }

}

security.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

    <http pattern="/resources/**" security="none" />
    <http pattern="/project/" security="none" />

    <http use-expressions="true">
        <!-- Authentication policy -->
        <form-login login-page="/signin" login-processing-url="/signin/authenticate" authentication-failure-url="/signin?error=bad_credentials" />
        <logout logout-url="/signout" delete-cookies="JSESSIONID" />
        <intercept-url pattern="/addcourse" access="isAuthenticated()" />
        <intercept-url pattern="/courses/**/**/edit" access="isAuthenticated()" />
        <intercept-url pattern="/users/**/edit" access="isAuthenticated()" />
    </http>

    <authentication-manager alias="authenticationManager">
        <authentication-provider>
            <password-encoder ref="passwordEncoder" />
            <jdbc-user-service data-source-ref="dataSource" 
                            users-by-username-query="select username, password, true from Account where username = ?"
                            authorities-by-username-query="select username, 'ROLE_USER' from Account where username = ?"/>
        </authentication-provider>
        <authentication-provider>
            <user-service>
                <user name="admin" password="admin" authorities="ROLE_USER, ROLE_ADMIN" />
            </user-service>
        </authentication-provider>
    </authentication-manager>

</beans:beans>

そして、これは UserDetailsS​​ervice を実装する私の試みです

public class RepositoryUserDetailsService implements UserDetailsService {

    private final AccountRepository accountRepository;

    @Autowired
    public RepositoryUserDetailsService(AccountRepository repository) {
        this.accountRepository = repository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Account user = accountRepository.findAccountByUsername(username);

        if (user == null) {
            throw new UsernameNotFoundException("No user found with username: " + username);
        }

        return user;

    }
}

それでも同じエラーが表示されます。どこかに UserDetailsS​​ervice を追加する必要がありますか? これは私の最初の質問とは別のものになり始めています。おそらく別の質問を開始する必要があります。

これについては私の経験不足で申し訳ありません。私は読み上げなければなりません。

4

2 に答える 2

6

Spring Security を使用している場合は、スクリプトレットを捨てて、代わりに Spring Security カスタム タグライブラリを使用することをお勧めします。

http://docs.spring.io/spring-security/site/docs/3.1.4.RELEASE/reference/taglibs.html

モデルにメソッドを持つid属性があり、モデルが Spring Security のインターフェースを実装している限り (そうあるべきです) 、次のタグを使用して属性にアクセスできるはずです。getId()AccountAccountUserDetailsid

<security:authentication property="principal.id" />

インラインで使用するか、値を別の変数に割り当てることができます。

<security:authentication property="principal.id" var="accountId" />
...
${accountId}

これは、オブジェクトの任意のプロパティに対して機能しますAccount(ユーザーが認証されている限り、明らかに)。

質問の更新後に編集:

UserDetailsServiceの実装がのインスタンスを返すことを確認してくださいAccount。実際にAccountタイプをプリンシパルとして使用していないようです。

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {        
    Account account = ... // fetch your Account
    return account;
}

質問が更新された後の編集#2

問題はここにあります:

<jdbc-user-service data-source-ref="dataSource" 
    users-by-username-query="select username, password, true from Account where username = ?"
    authorities-by-username-query="select username, 'ROLE_USER' from Account where username = ?"/>

いわば「ショートカット」を使用して、UserDetailsSpring Security によって提供されるインターフェイスのデフォルト実装、具体的には を取得していますorg.springframework.security.core.userdetails.User。ただし、プリンシパルのタイプはAccount. これは自動的に起こるわけではありません。要素を使用する代わりに、jdbc-user-serviceの独自の実装を提供する必要がありますUserDetailsService。このようなもの:

<authentication-manager ...>
    <authentication-provider user-service-ref="myUserDetailsServiceImpl"/>
</authentication-manager>

...次のUserDetailsServiceような実装で:

@Service
public class MyUserDetailsServiceImpl implements UserDetailsService {
    ...
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Account account = ...// load your Account
        return account;
    }
}

そうすれば、あなたは正しい方向に向かうはずです。

于 2013-10-27T18:42:38.627 に答える
0

春については何も知りませんが、ID プリンシパルをどのように拡張したかによっては、取得できるユーザー ID のような他のフィールドがあるかもしれません。春にセキュリティを構成し、独自のアイテムを ID コレクションに追加することもできます。それが不可能な場合は、(一部のリポジトリで) メール アドレスに基づいてユーザー ID を検索し、モデル/ビュー バッグに入力する actionfilter を検討してください。必要な各コントローラーまたはアクションを装飾します。

于 2013-10-27T18:20:16.147 に答える