代码之家  ›  专栏  ›  技术社区  ›  greyfox

未正确设置Spring安全角色

  •  0
  • greyfox  · 技术社区  · 10 年前

    我已经从SpringSecurity实现了我自己的User和UserDetailsService,因为我需要在SpringSecurity保存的用户对象中存储其他信息。然而,我认为角色设置不正确。在数据库和应用程序中,用户可以有0,1个或多个角色。

    我的胸腺视图中有以下块

    <!-- header / navigation based on role of the user-->
        <th:block sec:authorize="hasRole('ROLE_ADMIN')">
            <header th:include="fragments/header :: headerAdmin"></header>
        </th:block>
        <th:block sec:authorize="hasRole('ROLE_USER')">
            <header th:include="fragments/header :: headerUser"></header>
        </th:block>
        <th:block sec:authorize="isAnonymous()">
            <header th:include="fragments/header :: headerPublic"></header>
        </th:block>
    

    我一登录,这些都没有显示,但我至少在数据库中有ROLE_ADMIN。

    以下是我对UserDetailsService的实现

    @Service
    public class CustomUserDetailsService implements UserDetailsService {
    
        private static final Logger logger = LoggerFactory.getLogger(CustomUserDetailsService.class);
    
        @Autowired
        private UserMapper userMapper;
    
        @Override
        public CustomUser loadUserByUsername(String email) throws UsernameNotFoundException {
    
            logger.info("Authenticating user with email {}", email);
            User user = userMapper.getUserByEmail(email);
            if (user == null) {
                throw new UsernameNotFoundException(String.format("User with email %s was not found", email));
            }
            return new CustomUser(user);
        }
    }
    

    以及我的用户实施

    public class CustomUser extends org.springframework.security.core.userdetails.User {
    
        private User user;
    
        public CustomUser(User user) {
            super(user.getEmail(),user.getPassword(), AuthorityUtils.createAuthorityList(user.getRoles().toString()));
            this.user = user;
        }
    
        public User getUser() {
            return user;
        }
    
        public void setUser(User user) {
            this.user = user;
        }
    
        public Collection<String> getRoles() {
            return this.user.getRoles();
        }
    
        @Override
        public String toString() {
            return MoreObjects.toStringHelper(this)
                    .add("user", user)
                    .toString();
        }
    }
    

    我将此块添加到控制器中

    @Controller
    public class HomeController {
    
        private static Logger logger = LoggerFactory.getLogger(HomeController.class);
    
        @RequestMapping(value = "/", method = RequestMethod.GET)
        public String getHome() {
            Collection<SimpleGrantedAuthority> authorities = (Collection<SimpleGrantedAuthority>)    SecurityContextHolder.getContext().getAuthentication().getAuthorities();
            logger.info(authorities.toString());
            return "home/index";
        }
    }
    

    它打印了以下内容:

    16:30:04.920 INFO  HomeController.getHome - [[ROLE_ADMIN]]
    

    作为参考,这是MyBatis正在填充的用户域对象

    public class User implements Serializable {
    
        private long id;
        private String email;
        private String password;
        private String firstName;
        private String lastName;
        private long institutionId;
        private char locked;
        private Date createdAt;
        private Date lastLogin;
        private int failedLoginAttempts;
        private Collection<String> roles;
    
        public User() {
        }
    
        public long getId() {
            return id;
        }
    
        public void setId(long id) {
            this.id = id;
        }
    
        public String getEmail() {
            return email;
        }
    
        public void setEmail(String email) {
            this.email = email;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public String getFirstName() {
            return firstName;
        }
    
        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }
    
        public String getLastName() {
            return lastName;
        }
    
        public void setLastName(String lastName) {
            this.lastName = lastName;
        }
    
        public long getInstitutionId() {
            return institutionId;
        }
    
        public void setInstitutionId(long institutionId) {
            this.institutionId = institutionId;
        }
    
        public char getLocked() {
            return locked;
        }
    
        public void setLocked(char locked) {
            this.locked = locked;
        }
    
        public Collection<String> getRoles() {
            return roles;
        }
    
        public void setRoles(Collection<String> roles) {
            this.roles = roles;
        }
    
        public Date getCreatedAt() {
            return createdAt;
        }
    
        public void setCreatedAt(Date createdAt) {
            this.createdAt = createdAt;
        }
    
        public Date getLastLogin() {
            return lastLogin;
        }
    
        public void setLastLogin(Date lastLogin) {
            this.lastLogin = lastLogin;
        }
    
        public int getFailedLoginAttempts() {
            return failedLoginAttempts;
        }
    
        public void setFailedLoginAttempts(int failedLoginAttempts) {
            this.failedLoginAttempts = failedLoginAttempts;
        }
    }
    

    还有MyBatis Mapper

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="org.ohtech.innovationexchange.persistence.UserMapper">
    
        <resultMap id="userMap" type="org.ohtech.innovationexchange.domain.User">
            <id column="ID" property="id" />
            <id column="EMAIL" property="email" />
            <id column="PASSWORD" property="password" />
            <id column="FIRST_NAME" property="firstName" />
            <id column="LAST_NAME" property="lastName" />
            <id column="INSTITUTION_ID" property="institutionId" />
            <id column="LOCKED" property="locked" />
            <id column="CREATED_AT" property="createdAt" />
            <id column="LAST_LOGIN" property="lastLogin" />
            <id column="FAILED_LOGIN_ATTEMPTS" property="failedLoginAttempts" />
            <collection property="roles" ofType="String">
                <id column="SPRING_NAME" />
            </collection>
        </resultMap>
    
        <select id="getUserByEmail" statementType="PREPARED" parameterType="String" resultMap="userMap">
            SELECT
              u.ID,
              u.EMAIL,
              u.PASSWORD,
              u.FIRST_NAME,
              u.LAST_NAME,
              u.INSTITUTION_ID,
              u.LOCKED,
              u.CREATED_AT,
              u.LAST_LOGIN,
              u.FAILED_LOGIN_ATTEMPTS,
              r.SPRING_NAME
            FROM T_USER u
            INNER JOIN T_USER_ROLE tr
              ON u.ID = tr.USER_ID
            INNER JOIN T_ROLE r
              ON tr.ROLE_ID = r.ID
            WHERE EMAIL = #{email}
        </select>
    </mapper>
    

    更新:

    我将CustomUserDetailsService更新为以下内容:

    @Service
    public class CustomUserDetailsService implements UserDetailsService {
    
        private static final Logger logger = LoggerFactory.getLogger(CustomUserDetailsService.class);
    
        @Autowired
        private UserMapper userMapper;
    
        @Override
        public CustomUser loadUserByUsername(String email) throws UsernameNotFoundException {
    
            logger.info("Authenticating user with email {}", email);
            User user = userMapper.getUserByEmail(email);
            if (user == null) {
                throw new UsernameNotFoundException(String.format("User with email %s was not found", email));
            }
    
            Collection<GrantedAuthority> authorities = new HashSet<>();
            for (String role : user.getRoles()) {
                authorities.add(new SimpleGrantedAuthority(role));
            }
    
            return new CustomUser(user, authorities);
        }
    }
    

    自定义用户:

    public class CustomUser extends org.springframework.security.core.userdetails.User {
    
        private User user;
    
        public CustomUser(User user, Collection<GrantedAuthority> grantedAuthorities) {
            super(user.getEmail(),user.getPassword(), grantedAuthorities);
            this.user = user;
        }
    
        public User getUser() {
            return user;
        }
    
        public void setUser(User user) {
            this.user = user;
        }
    
        public Collection<String> getRoles() {
            return this.user.getRoles();
        }
    
        @Override
        public String toString() {
            return MoreObjects.toStringHelper(this)
                    .add("user", user)
                    .toString();
        }
    }
    

    现在正在打印:

    18:02:29.045 INFO  HomeController.getHome - [ROLE_ADMIN, ROLE_INSTITUTION_USER]
    

    但我的Thymelaf秒针仍然不起作用。

    1 回复  |  直到 10 年前
        1
  •  1
  •   holmis83    10 年前

    这是错误的:

    AuthorityUtils.createAuthorityList(user.getRoles().toString())
    

    因为 createAuthorityList 将不会分析集合的字符串表示形式。相反,您应该使用以下内容:

    AuthorityUtils.createAuthorityList(user.getRoles().toArray(new String[0]))