解決方法がわからない設計上の問題があります。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つの解決策を考えてきましたが、よくわかりません:
- ID も含めるようにプリンシパルを変更します。これを行う方法がわからず、トピックに関する適切な情報を見つけるのに問題があります。
- ユーザー全体を含むすべてのコントローラーにモデル属性を追加しますが、これはこのように本当に醜いでしょう。
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>
そして、これは UserDetailsService を実装する私の試みです
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;
}
}
それでも同じエラーが表示されます。どこかに UserDetailsService を追加する必要がありますか? これは私の最初の質問とは別のものになり始めています。おそらく別の質問を開始する必要があります。
これについては私の経験不足で申し訳ありません。私は読み上げなければなりません。