liukaihandsome
liukaihandsome
2011-03-21 14:34
浏览 674
已采纳

spring3MVC +spring security3 关于扩展UserDetailsService 无法注入service的疑问.

问题描述:
我想用的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]

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

9条回答 默认 最新

  • archy123
    archy123 2011-03-22 10:00
    已采纳

    把[code="java"]
    springSecurityFilterChain
    org.springframework.web.filter.DelegatingFilterProxy

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

    [/code]
    放到 [code="java"]
    org.springframework.web.context.ContextLoaderListener
    [/code]
    前试试

    点赞 评论
  • archy123
    archy123 2011-03-22 09:48

    贴出 web.xml看下。。可能顺序弄错了你

    点赞 评论
  • archy123
    archy123 2011-03-22 11:00

    事务注解去掉试试。。 :oops:

    点赞 评论
  • archy123
    archy123 2011-03-22 11:01

    [code="java"]@Transactional(readOnly = true) [/code]

    点赞 评论
  • yanwt
    yanwt 2011-03-23 18:07

    springsecurity3中增加

    点赞 评论
  • weixin_42551056
    马乾 2011-03-31 18:46

    兄弟,出错信息都已经很详细了吧,你的resource加载有问题导致nullPointException

    点赞 评论
  • iteye_11009
    iteye_11009 2011-04-04 07:56

    看视路径问题

    点赞 评论
  • ylsq
    ylsq 2012-05-29 21:11

    我下载下来 accountService还是为空。
    把listener放到filter后面还是不行

    点赞 评论
  • weixin_42551207
    呆萌暖暖吐舌头 2013-11-11 22:48


    加在你要配置的spring security xml 文件里面,自动注入就可以了

    点赞 评论

相关推荐