2013-01-10 16 views
9

Jestem całkiem nowy, aby wiosną i mam ten problem ze sprężyną bezpieczeństwa. W rzeczywistości działa tylko bez mojej niestandardowej implementacji UserDetailsService.Spring Security - UserDetails Implementacja usługi - Logowanie nie powiodło się

konto i rola Przedmioty

@Entity 
@Table(name="ACCOUNT", uniqueConstraints = {@UniqueConstraint (columnNames = "USERNAME"),  @UniqueConstraint (columnNames = "EMAIL")}) 
public class Account implements Serializable { 
private static final long serialVersionUID = 2872791921224905344L; 

@Id 
@GeneratedValue(strategy = GenerationType.AUTO) 
@Column(name="ID") 
private Integer id; 

@Column(name="USERNAME") 
@NotNull 
private String username; 

@Column(name="PASSWORD") 
@NotNull 
private String password; 

@Column(name="EMAIL") 
@NotNull 
@Email 
private String email; 

@Column(name="ENABLED") 
private boolean enabled; 

@ManyToMany(cascade= CascadeType.ALL) 
@JoinTable(name="ACCOUNT_ROLE", joinColumns = {@JoinColumn (name="ID_ACCOUNT")}, inverseJoinColumns ={ @JoinColumn (name="ID_ROLE")}) 
private Set<Role> roles = new HashSet<Role>(0); 

Role

@Entity 
@Table(name="ROLE", uniqueConstraints={@UniqueConstraint (columnNames="NAME")}) 
public class Role implements Serializable{ 

private static final long serialVersionUID = -9162292216387180496L; 

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

@Column(name = "NAME") 
@NotNull 
private String name; 

@ManyToMany(mappedBy = "roles") 
private Set<Account> accounts = new HashSet<Account>(0); 

Adapter dla UserDetails

@SuppressWarnings({ "serial", "deprecation" }) 
public class UserDetailsAdapter implements UserDetails { 

private Account account; 

public UserDetailsAdapter(Account account) {this.account = account;} 

public Account getAccount() {return account;} 

public Integer getId(){return account.getId();} 

public String getEmail() {return account.getEmail();} 

@Override 
public Collection<? extends GrantedAuthority> getAuthorities() { 
    Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>(); 
    for (Role r :account.getRoles()) { 
     authorities.add(new GrantedAuthorityImpl(r.getName())); 
    } 
    return authorities; 
} 

Zwyczaj UserDetailsService

@Service("customUserDetailsService") 
public class CustomUserDetailsService implements UserDetailsService { 
@Inject AccountDao accountDao; 
@Inject RoleDao roleDao; 


@Override 
public UserDetails loadUserByUsername(String username) 
     throws UsernameNotFoundException { 
    Account account= accountDao.findByUsername(username); 



    if(account==null) {throw new UsernameNotFoundException("No such user: " + username); 
    } else if (account.getRoles().isEmpty()) { 
     throw new UsernameNotFoundException("User " + username + " has no authorities"); 
       } 
    UserDetailsAdapter user = new UserDetailsAdapter(account); 
    return user; 
    } 

web.xml

<?xml version="1.0" encoding="UTF-8"?> 
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 

<filter> 
     <filter-name>springSecurityFilterChain</filter-name> 
     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 
</filter> 

<filter-mapping> 
     <filter-name>springSecurityFilterChain</filter-name> 
     <url-pattern>/*</url-pattern> 
</filter-mapping> 

<!-- The definition of the Root Spring Container shared by all Servlets and Filters --> 
<context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value>/WEB-INF/spring/root-context.xml 
        /WEB-INF/spring/appServlet/security- context.xml</param-value> 
</context-param> 

<!-- Creates the Spring Container shared by all Servlets and Filters --> 
<listener> 
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
</listener> 

<!-- Creates the Filters to handle hibernate lazyload exception --> 

<filter> 
    <filter-name>OpenSessionInViewFilter</filter-name> 
    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class> 
</filter> 

<filter-mapping> 
    <filter-name>OpenSessionInViewFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 


<!-- Processes application requests --> 
<servlet> 
    <servlet-name>appServlet</servlet-name> 
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
    <init-param> 
     <param-name>contextConfigLocation</param-name> 
     <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value> 
    </init-param> 
    <load-on-startup>1</load-on-startup> 
</servlet> 

<servlet-mapping> 
    <servlet-name>appServlet</servlet-name> 
    <url-pattern>/</url-pattern> 
</servlet-mapping> 

</web-app> 

korzeń-context

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

<!-- Root Context: defines shared resources visible to all other web components --> 
<context:property-placeholder properties-ref="deployProperties"/> 
<!-- Remember to correctly locate the right file for properties configuration(example DB connection parameters) --> 
<bean id="deployProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean" 
    p:location="/WEB-INF/spring/appServlet/spring.properties" /> 

    <context:annotation-config/> 
    <context:component-scan base-package="org.treci"> 
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 
    </context:component-scan> 

    <import resource="/appServlet/data-context.xml"/> 

Kontekst zabezpieczeń

<?xml version="1.0" encoding="UTF-8"?> 
<beans:beans xmlns="http://www.springframework.org/schema/security" 
xmlns:beans="http://www.springframework.org/schema/beans" 
xmlns:p="http://www.springframework.org/schema/p" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:context="http://www.springframework.org/schema/context" 
xmlns:tx="http://www.springframework.org/schema/tx" 
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.xsd 
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd 
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"> 

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


<http auto-config="true" use-expressions="true"> 
    <intercept-url pattern="/" access="permitAll"/> 
    <intercept-url pattern="/login" access="permitAll"/> 
    <intercept-url pattern="/login-success" access="hasRole('ROLE_ADMIN')"/> 

    <form-login login-page="/login" 
    default-target-url="/login-success" 
    authentication-failure-url="/login-failed"/> 
    <logout logout-success-url="/logout"/> 
</http> 

<beans:bean id="customUserDetailsService" class="org.treci.app.service.CustomUserDetailsService"></beans:bean> 


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

</beans:beans> 

Mam nadzieję, że niektórzy z was może pomóc, ratuj mnie:)

+2

Czy masz jakieś logi? Mam podobny problem, gdy moja UserDetailsService nie była @Transactional. – madhead

+0

Jak dokładnie to nie działa? –

+0

po podaniu nazwy użytkownika i hasła przynosi mi zawsze uwierzytelnianie-niepowodzenie-url = "/ login-failed"/ Dostęp do danych do DB działa właściwie ponieważ powoduje drukowanie na stronie internetowej zadania DAO –

Odpowiedz

10

Oto jak rozwiązałem problem:

w CustomDetailsService Zwróciłem obiekt UserDetails przy użyciu adaptera, jak widać.

Patrząc na samouczek, zdałem sobie sprawę, że powinienem zwrócić obiekt org.springframework.security.core.userdetails.User.

Oto moja nowa realizacja CustomDetailsService:

@Transactional(readOnly=true) 
@Service("customUserDetailsService") 
public class CustomUserDetailsService implements UserDetailsService { 
@Inject AccountDao accountDao; 

@Override 
public UserDetails loadUserByUsername(String username) 
     throws UsernameNotFoundException { 
    Account account= accountDao.findByUsername(username); 

    if(account==null) {throw new UsernameNotFoundException("No such user: " + username); 
    } else if (account.getRoles().isEmpty()) { 
     throw new UsernameNotFoundException("User " + username + " has no authorities"); 
       } 

    boolean accountNonExpired = true; 
    boolean credentialsNonExpired = true; 
    boolean accountNonLocked = true; 

    return new User(
      account.getUsername(), 
      account.getPassword().toLowerCase(), 
      account.isEnabled(), 
      accountNonExpired, 
      credentialsNonExpired, 
      accountNonLocked, 
      getAuthorities(account.getRoles())); 
    } 

public List<String> getRolesAsList(Set<Role> roles) { 
    List <String> rolesAsList = new ArrayList<String>(); 
    for(Role role : roles){ 
     rolesAsList.add(role.getName()); 
    } 
    return rolesAsList; 
} 

public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) { 
    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); 
    for (String role : roles) { 
     authorities.add(new SimpleGrantedAuthority(role)); 
    } 
    return authorities; 
} 

public Collection<? extends GrantedAuthority> getAuthorities(Set<Role> roles) { 
    List<GrantedAuthority> authList = getGrantedAuthorities(getRolesAsList(roles)); 
    return authList; 
} 

} 
+1

Jeśli używasz LDAP do uwierzytelniania, bazy danych do autoryzacji ról i nie chcesz przekazywać hasła do usługi UserDetailsService, możesz zamiast tego podać ciąg znaków (np. "LDAP"). Nie zaakceptuje wartości pustej. –

+0

Więc nie używasz wtedy klasy UserDetailsAdapter? – Stephane

Powiązane problemy