私は春にまったく慣れていないので、春のセキュリティでこの問題を抱えています。実際には、カスタムUserDetailsService実装なしでのみ機能します。
アカウントおよびロールオブジェクト
@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);
役割
@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);
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;
}
カスタム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>
ルートコンテキスト
<?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"/>
セキュリティコンテキスト
<?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>
私はあなたの何人かが助けてくれることを願っています、私を救ってください:)
これが私が問題を解決した方法です:
customDetailsServiceで、ご覧のとおり、アダプターを使用してUserDetailsオブジェクトを返していました。
いくつかのチュートリアルを見て、org.springframework.security.core.userdetails.Userオブジェクトを返す必要があることに気付きました。
これが私の新しい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;
}
}