2013-10-27 29 views
2

我有一個設計問題,我不知道如何解決。我使用Spring 3.2.4和Spring安全性3.1.4。達到用戶ID而不通過每個控制器

我在我的數據庫中的客戶表看起來像這樣:

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每個用戶都必須鏈接到配置文件。

如何從每個頁面訪問用戶標識?

我一直在想兩種解決方案,但我不知道:

  1. 變化主要包含了ID爲好,不知道如何做到這一點,有問題,找到就不錯了信息話題。
  2. 將模型屬性添加到包含整個用戶的所有控制器,但這樣會非常難看。

Account account = entityManager.find(Account.class, email);
model.addAttribute("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="https://stackoverflow.com/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

的嘗試210

仍給我同樣的錯誤,我需要添加UserDetailsS​​ervice的地方嗎? 與我最初的問題相比,這開始是別的,我可能會開始另一個問題。

對不起,我缺乏這方面的經驗。我必須閱讀。

回答

6

如果你正在使用Spring Security的,它可能是有益的溝小腳本,而是使用Spring Security的自定義標籤庫:只要

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

因爲你有一個id屬性與getId()方法上您的Account模型和您的Account模型正在實現Spring Security的UserDetails接口(因爲它應該是),那麼您應該能夠使用以下標記訪問id屬性:

<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 = ?"/> 

您正在使用「快捷方式」,這樣來講話獲取的默認實現Spring Security提供的接口UserDetails,具體爲org.springframework.security.core.userdetails.User。但是,您希望您的委託人的類型爲Account。這不會自動發生。您應該提供您自己的UserDetailsService實施,而不是使用jdbc-user-service元素。事情是這樣的:

<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; 
    } 
} 

,應該讓你在正確的方向前進。

0

我對春天一無所知,但根據他們如何擴展身份認證主體,可能會有其他字段,如可以抓取的用戶ID。您也可以在春季配置安全性,並將自己的項目添加到身份集合中。如果這不可行,那麼考慮一個actionfilter,它根據電子郵件地址(在某個存儲庫中)查找用戶標識並填充模型/視圖包。裝飾每個控制器或需要它的動作。

+1

unforunetly校長截至目前只有用戶名和其他一些重要的領域。我會研究你的其他建議 – nilsi

相關問題