问题描述:
我想用的spring3MVC+spring security3 实现登录权限的扩展.即扩展UserDetailsService 以达到从持久层上控制登录信息.
但是现在的问题是我启动服务器后,登录时在UserDetailsService 中 service层的方法无法注入.
如下图
[img]http://dl.iteye.com/upload/attachment/441866/0e084199-5973-3d55-a691-b8e1de9559ff.png[/img]
注意图中红线的地方. accountService为null.表示注入失败.
所以我想请教下大家:为什么会出现accountService为null 的问题.
我把主要的代码贴出来并在最后提供例子的下载.
首先是项目文件结构.
[img]http://dl.iteye.com/upload/attachment/441868/e7f16960-ef9f-3f2a-9491-9602bac6bfbe.png[/img]
[b]下面这段是继承UserDetailsService以实现持久层关联登录.[/b]
[code="java"]
@Transactional(readOnly = true)
public class UserDetailsServiceImpl implements UserDetailsService {
private static final Logger logger = LoggerFactory
.getLogger(UserDetailsServiceImpl.class);
@Resource(name = "accountService")
private IAccountService accountService;
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
logger.info("username:" + username);
User user = accountService.getUserInfo(username);
if (user == null) {
throw new UsernameNotFoundException("用户" + username + "不存在!");
}
Set<GrantedAuthority> grantedAuths = obtainGrantedAuthorities(user);
boolean enabled = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
UserDetails userDetails = new org.springframework.security.core.userdetails.User(
username, user.getPassword(), enabled, accountNonExpired,
credentialsNonExpired, accountNonLocked, grantedAuths);
return userDetails;
}
private Set<GrantedAuthority> obtainGrantedAuthorities(User user) {
Set<GrantedAuthority> authSet = Sets.newHashSet();
for (Role role : user.getRoleList()) {
for (Authority authority : role.getAuthorityList()) {
logger.info("authority is :" + authority.getPrefixedName());
authSet.add(new GrantedAuthorityImpl(authority
.getPrefixedName()));
}
}
return authSet;
}
}[/code]
[b]service接口[/b]
[code="java"]public interface IAccountService {
/**
* 根据用户登录名获得对应的权限信息.
*/
public User getUserInfo(String userName);
}[/code]
[b]
实现IAccountService的类[/b]
[code="java"]
@Service("accountService")
@Transactional
public class AccountService implements IAccountService {
@Resource(name="accountDao")
private IAccountDao dao;
private static final Logger logger = LoggerFactory
.getLogger(AccountService.class);
public User getUserInfo(String userName) {
// 根据登录名(userName)获得对应的信息
User user = dao.getUserByloginName(userName);
// 根据登录名获得对应的角色名.如 用户admin拥有"用户","管理员"这两个角色
List<Role> roleList = dao.getRoleByUserName(userName);
for (int i = 0; i < roleList.size(); i++) {
// 根据角色的ID查询出每个角色对应的权限.
List<Authority> authorityList = dao.getAuthorityByRoleId(roleList
.get(i).getId());
Role role = new Role();
// 将查询出来的权限信息放入Role中的authorityList.
role.setAuthorityList(authorityList);
// 对象role放入集合中
roleList.add(role);
}
// 将查询出来的角色信息(包含各个角色信息对应的权限信息)装入User里的roleList中.
user.setRoleList(roleList);
return user;
}
}[/code]
[b]IAccountDao接口[/b]
[code="java"]
public interface IAccountDao {
/**
* 根据loginName获得对应用户信息
*
* @return
*/
public User getUserByloginName(String loginName);
/**
* 根据登录名获得对应的角色.
*
* @param userName
* @return
*/
public List<Role> getRoleByUserName(String userName);
/**
* 根据角色ID获得对应的权限ID
*
* @param roleId
* @return
*/
public List<Authority> getAuthorityByRoleId(int roleId);
}[/code]
[b]实现IAccountDao接口的类
[/b]
[code="java"]
@Repository("accountDao")
public class AccountDao implements IAccountDao {
private static final Logger logger = LoggerFactory.getLogger(AccountDao.class);
private SimpleJdbcTemplate jdbcTemplate;
@Resource(name = "dataSource")
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new SimpleJdbcTemplate(dataSource);
}
public User getUserByloginName(String loginName) {
String sql = "SELECT id,email,login_name,name,password FROM acct_user WHERE login_name = ?";
return jdbcTemplate.queryForObject(sql,
new BeanPropertyRowMapper<User>(User.class),
new Object[] { loginName });
}
public List<Role> getRoleByUserName(String userName) {
String sql = "SELECT acct_role.id,acct_role.name FROM acct_user LEFT JOIN acct_user_role ON acct_user_role.user_id=acct_user.id LEFT JOIN acct_role ON acct_role.id=acct_user_role.role_id WHERE acct_user.login_name = ?";
return jdbcTemplate.query(sql, new BeanPropertyRowMapper<Role>(
Role.class), new Object[] { userName });
}
public List<Authority> getAuthorityByRoleId(int roleId) {
String sql = "SELECT acct_authority.id,acct_authority.name,acct_authority.url FROM acct_authority LEFT JOIN acct_role_authority ON acct_authority.id=acct_role_authority.authority_id LEFT JOIN acct_role ON acct_role.id=acct_role_authority.role_id WHERE acct_role.id= ?";
return jdbcTemplate.query(sql, new BeanPropertyRowMapper<Authority>(
Authority.class), new Object[] { roleId });
}[/code]
然后是springsecurity3的配置文件
[code="java"]
<?xml version="1.0" encoding="UTF-8"?>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd"
default-lazy-init="true">
<sec:http auto-config="true" use-expressions="true"
access-denied-page="/denied">
<sec:intercept-url pattern="/resources/**" filters="none" />
<sec:intercept-url pattern="/" access="isAuthenticated()" />
<sec:intercept-url pattern="/login" access="permitAll" />
<!-- <sec:intercept-url pattern="/" access="hasRole('ROLE_ADMIN')" /> -->
<sec:form-login login-page="/login"
authentication-failure-url="/login?error=1" default-target-url="/" />
<sec:logout invalidate-session="true" logout-success-url="/login"
logout-url="/logout" />
</sec:http>
<sec:authentication-manager>
<sec:authentication-provider
user-service-ref="customUserDetailsService">
<sec:password-encoder hash="plaintext" />
</sec:authentication-provider>
</sec:authentication-manager>
<bean id="customUserDetailsService" class="com.sjax.myapp.service.UserDetailsServiceImpl" />
[/code]