实现userdetails
首先,我们将在数据库中需要以下表格:
CREATE TABLE IF NOT EXISTS `mydb`.`security_role` (`id` INT(11) NOT NULL AUTO_INCREMENT ,`name` VARCHAR(50) NULL DEFAULT NULL ,PRIMARY KEY (`id`) )ENGINE = InnoDBAUTO_INCREMENT = 4DEFAULT CHARACTER SET = latin1;CREATE TABLE IF NOT EXISTS `mydb`.`user` (`id` INT(11) NOT NULL AUTO_INCREMENT ,`first_name` VARCHAR(45) NULL DEFAULT NULL ,`family_name` VARCHAR(45) NULL DEFAULT NULL ,`dob` DATE NULL DEFAULT NULL ,`password` VARCHAR(45) NOT NULL ,`username` VARCHAR(45) NOT NULL ,`confirm_password` VARCHAR(45) NOT NULL ,`active` TINYINT(1) NOT NULL ,PRIMARY KEY (`id`) ,UNIQUE INDEX `username` (`username` ASC) )ENGINE = InnoDBAUTO_INCREMENT = 9DEFAULT CHARACTER SET = latin1;CREATE TABLE IF NOT EXISTS `mydb`.`user_security_role` (`user_id` INT(11) NOT NULL ,`security_role_id` INT(11) NOT NULL ,PRIMARY KEY (`user_id`, `security_role_id`) ,INDEX `security_role_id` (`security_role_id` ASC) ,CONSTRAINT `user_security_role_ibfk_1`FOREIGN KEY (`user_id` )REFERENCES `mydb`.`user` (`id` ),CONSTRAINT `user_security_role_ibfk_2`FOREIGN KEY (`security_role_id` )REFERENCES `mydb`.`security_role` (`id` ))ENGINE = InnoDBDEFAULT CHARACTER SET = latin1;
显然,表用户将拥有用户,表security_role将拥有安全角色,而user_security_roles将拥有关联。 为了使实现尽可能简单,security_role表中的条目应始终以“ ROLE_”开头,否则我们将需要封装(本文将不涉及)。
因此,我们执行以下语句:
insert into security_role(name) values ('ROLE_admin');insert into security_role(name) values ('ROLE_Kennel_Owner');insert into security_role(name) values ('ROLE_User');insert into user (first_name,family_name,password,username,confirm_password,active)values ('ioannis','ntantis','123456','giannisapi','123456',1);insert into user_security_role (user_id,security_role_id) values (1,1);
因此,执行这些命令后,我们将得到以下内容:
三种不同的安全角色
一位用户名为“ giannisapi”的用户
我们已将角色“ ROLE_admin”赋予用户“ giannisapi”
现在,一切都已在数据库端完成,我们将移至Java端,看看需要做什么。
首先,我们将创建必要的DTO(有多种工具可以为您自动从数据库生成DTO):
package org.intan.pedigree.form;import java.io.Serializable;import java.util.Collection;import java.util.Date;import java.util.Set;import javax.persistence.Basic;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.JoinColumn;import javax.persistence.JoinTable;import javax.persistence.ManyToMany;import javax.persistence.NamedQueries;import javax.persistence.NamedQuery;import javax.persistence.Table;import javax.persistence.Temporal;import javax.persistence.TemporalType;/**** @author intan*/@Entity@Table(name = 'user', catalog = 'mydb', schema = '')@NamedQueries({@NamedQuery(name = 'UserEntity.findAll', query = 'SELECT u FROM UserEntity u'),@NamedQuery(name = 'UserEntity.findById', query = 'SELECT u FROM UserEntity u WHERE u.id = :id'),@NamedQuery(name = 'UserEntity.findByFirstName', query = 'SELECT u FROM UserEntity u WHERE u.firstName = :firstName'),@NamedQuery(name = 'UserEntity.findByFamilyName', query = 'SELECT u FROM UserEntity u WHERE u.familyName = :familyName'),@NamedQuery(name = 'UserEntity.findByDob', query = 'SELECT u FROM UserEntity u WHERE u.dob = :dob'),@NamedQuery(name = 'UserEntity.findByPassword', query = 'SELECT u FROM UserEntity u WHERE u.password = :password'),@NamedQuery(name = 'UserEntity.findByUsername', query = 'SELECT u FROM UserEntity u WHERE u.username = :username'),@NamedQuery(name = 'UserEntity.findByConfirmPassword', query = 'SELECT u FROM UserEntity u WHERE u.confirmPassword = :confirmPassword'),@NamedQuery(name = 'UserEntity.findByActive', query = 'SELECT u FROM UserEntity u WHERE u.active = :active')})public class UserEntity implements Serializable {private static final long serialVersionUID = 1L;@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Basic(optional = false)@Column(name = 'id')private Integer id;@Column(name = 'first_name')private String firstName;@Column(name = 'family_name')private String familyName;@Column(name = 'dob')@Temporal(TemporalType.DATE)private Date dob;@Basic(optional = false)@Column(name = 'password')private String password;@Basic(optional = false)@Column(name = 'username')private String username;@Basic(optional = false)@Column(name = 'confirm_password')private String confirmPassword;@Basic(optional = false)@Column(name = 'active')private boolean active;@JoinTable(name = 'user_security_role', joinColumns = {@JoinColumn(name = 'user_id', referencedColumnName = 'id')}, inverseJoinColumns = {@JoinColumn(name = 'security_role_id', referencedColumnName = 'id')})@ManyToManyprivate Set securityRoleCollection;public UserEntity() {}public UserEntity(Integer id) {this.id = id;}public UserEntity(Integer id, String password, String username, String confirmPassword, boolean active) {this.id = id;this.password = password;this.username = username;this.confirmPassword = confirmPassword;this.active = active;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getFirstName() {return firstName;}public void setFirstName(String firstName) {this.firstName = firstName;}public String getFamilyName() {return familyName;}public void setFamilyName(String familyName) {this.familyName = familyName;}public Date getDob() {return dob;}public void setDob(Date dob) {this.dob = dob;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getConfirmPassword() {return confirmPassword;}public void setConfirmPassword(String confirmPassword) {this.confirmPassword = confirmPassword;}public boolean getActive() {return active;}public void setActive(boolean active) {this.active = active;}public Set getSecurityRoleCollection() {return securityRoleCollection;}public void setSecurityRoleCollection(Set securityRoleCollection) {this.securityRoleCollection = securityRoleCollection;}@Overridepublic int hashCode() {int hash = 0;hash += (id != null ? id.hashCode() : 0);return hash;}@Overridepublic boolean equals(Object object) {// TODO: Warning - this method won't work in the case the id fields are not setif (!(object instanceof UserEntity)) {return false;}UserEntity other = (UserEntity) object;if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {return false;}return true;}@Overridepublic String toString() {return 'org.intan.pedigree.form.User[id=' + id + ']';}}
package org.intan.pedigree.form;import java.io.Serializable;import java.util.Collection;import javax.persistence.Basic;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.ManyToMany;import javax.persistence.NamedQueries;import javax.persistence.NamedQuery;import javax.persistence.Table;/**** @author intan*/@Entity@Table(name = 'security_role', catalog = 'mydb', schema = '')@NamedQueries({@NamedQuery(name = 'SecurityRoleEntity.findAll', query = 'SELECT s FROM SecurityRoleEntity s'),@NamedQuery(name = 'SecurityRoleEntity.findById', query = 'SELECT s FROM SecurityRoleEntity s WHERE s.id = :id'),@NamedQuery(name = 'SecurityRoleEntity.findByName', query = 'SELECT s FROM SecurityRoleEntity s WHERE s.name = :name')})public class SecurityRoleEntity implements Serializable {private static final long serialVersionUID = 1L;@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Basic(optional = false)@Column(name = 'id')private Integer id;@Column(name = 'name')private String name;@ManyToMany(mappedBy = 'securityRoleCollection')private Collection userCollection;public SecurityRoleEntity() {}public SecurityRoleEntity(Integer id) {this.id = id;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Collection getUserCollection() {return userCollection;}public void setUserCollection(Collection userCollection) {this.userCollection = userCollection;}@Overridepublic int hashCode() {int hash = 0;hash += (id != null ? id.hashCode() : 0);return hash;}@Overridepublic boolean equals(Object object) {// TODO: Warning - this method won't work in the case the id fields are not setif (!(object instanceof SecurityRoleEntity)) {return false;}SecurityRoleEntity other = (SecurityRoleEntity) object;if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {return false;}return true;}@Overridepublic String toString() {return 'org.intan.pedigree.form.SecurityRole[id=' + id + ']';}}
现在我们已经有了DTO,让我们创建必要的DAO类:
package org.intan.pedigree.dao;import java.util.List;import java.util.Set;import org.hibernate.SessionFactory;import org.intan.pedigree.form.SecurityRoleEntity;import org.intan.pedigree.form.UserEntity;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Repository;@Repositorypublic class UserEntityDAOImpl implements UserEntityDAO{@Autowiredprivate SessionFactory sessionFactory;public void addUser(UserEntity user) {try {sessionFactory.getCurrentSession().save(user);} catch (Exception e) {System.out.println(e);}}public UserEntity findByName(String username) {UserEntity user = (UserEntity) sessionFactory.getCurrentSession().createQuery('select u from UserEntity u where u.username = '' + username + ''').uniqueResult();return user;}public UserEntity getUserByID(Integer id) {UserEntity user = (UserEntity) sessionFactory.getCurrentSession().createQuery('select u from UserEntity u where id = '' + id + ''').uniqueResult();return user;}public String activateUser(Integer id) {String hql = 'update UserEntityset active = :active where id = :id';org.hibernate.Query query = sessionFactory.getCurrentSession().createQuery(hql);query.setString('active','Y');query.setInteger('id',id);int rowCount = query.executeUpdate();System.out.println('Rows affected: ' + rowCount);return '';}public String disableUser(Integer id) {String hql = 'update UserEntity set active = :active where id = :id';org.hibernate.Query query = sessionFactory.getCurrentSession().createQuery(hql);query.setInteger('active',0);query.setInteger('id',id);int rowCount = query.executeUpdate();System.out.println('Rows affected: ' + rowCount);return '';}public void updateUser(UserEntity user) {try {sessionFactory.getCurrentSession().update(user);} catch (Exception e) {System.out.println(e);}}public List listUser() {return sessionFactory.getCurrentSession().createQuery('from UserEntity').list();}public void removeUser(Integer id) {UserEntity user = (UserEntity) sessionFactory.getCurrentSession().load(UserEntity.class, id);if (null != user) {sessionFactory.getCurrentSession().delete(user);}}public Set getSecurityRolesForUsername(String username) {UserEntity user = (UserEntity) sessionFactory.getCurrentSession().createQuery('select u from UserEntity u where u.username = '' + username + ''').uniqueResult();if (user!= null) {Set roles = (Set) user.getSecurityRoleCollection();if (roles != null && roles.size() > 0) {return roles;}}return null;}}
package org.intan.pedigree.dao;import java.util.List;import org.hibernate.Criteria;import org.hibernate.SessionFactory;import org.hibernate.criterion.Restrictions;import org.intan.pedigree.form.Country;import org.intan.pedigree.form.Kennel;import org.intan.pedigree.form.SecurityRoleEntity;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Repository;@Repositorypublic class SecurityRoleEntityDAOImpl implements SecurityRoleEntityDAO{@Autowiredprivate SessionFactory sessionFactory;public void addSecurityRoleEntity(SecurityRoleEntity securityRoleEntity) {try {sessionFactory.getCurrentSession().save(securityRoleEntity);} catch (Exception e) {System.out.println(e);}}public List listSecurityRoleEntity() {Criteria criteria = sessionFactory.getCurrentSession().createCriteria(SecurityRoleEntity.class);criteria.add(Restrictions.ne('name','ROLE_ADMIN' ));return criteria.list();}public SecurityRoleEntity getSecurityRoleEntityById(Integer id) {Criteria criteria = sessionFactory.getCurrentSession().createCriteria(SecurityRoleEntity.class);criteria.add(Restrictions.eq('id',id));return (SecurityRoleEntity) criteria.uniqueResult();}public void removeSecurityRoleEntity(Integer id) {SecurityRoleEntity securityRoleEntity = (SecurityRoleEntity) sessionFactory.getCurrentSession().load(SecurityRoleEntity.class, id);if (null != securityRoleEntity) {sessionFactory.getCurrentSession().delete(securityRoleEntity);}}}
现在,我们将为上述DAO创建服务层。
package org.intan.pedigree.service;import java.util.List;import org.intan.pedigree.dao.SecurityRoleEntityDAO;import org.intan.pedigree.form.SecurityRoleEntity;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;@Servicepublic class SecurityRoleEntityServiceImpl implements SecurityRoleEntityService{@Autowiredprivate SecurityRoleEntityDAO securityRoleEntityDAO;@Transactionalpublic void addSecurityRoleEntity(SecurityRoleEntity securityRoleEntity) {securityRoleEntityDAO.addSecurityRoleEntity(securityRoleEntity);}@Transactionalpublic List listSecurityRoleEntity() {return securityRoleEntityDAO.listSecurityRoleEntity();}@Transactionalpublic void removeSecurityRoleEntity(Integer id) {securityRoleEntityDAO.removeSecurityRoleEntity(id);}@Transactionalpublic SecurityRoleEntity getSecurityRoleEntityById(Integer id) {return securityRoleEntityDAO.getSecurityRoleEntityById( id);}}
在下面的UserDetails的Service层中,请注意它从org.springframework.security.core.userdetails.UserDetailsService实现了UserDetailsService。
package org.intan.pedigree.service;import org.intan.pedigree.dao.UserEntityDAO;import org.intan.pedigree.dao.UserEntityDAO;import org.intan.pedigree.form.UserEntity;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.dao.DataAccessException;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import org.springframework.security.core.userdetails.User;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.core.userdetails.UsernameNotFoundException;@Service('userDetailsService')public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UserEntityDAO dao;@Autowiredprivate Assembler assembler;@Transactional(readOnly = true)public UserDetails loadUserByUsername(String username)throws UsernameNotFoundException, DataAccessException {UserDetails userDetails = null;UserEntity userEntity = dao.findByName(username);if (userEntity == null)throw new UsernameNotFoundException('user not found');return assembler.buildUserFromUserEntity(userEntity);}}
您还在上面看到,loadUserByUsername方法返回assembler.buildUserFromUserEntity的结果。 简而言之,汇编器的此方法要做的是从给定的UserEntity DTO构造一个org.springframework.security.core.userdetails.User对象。 下面给出了Assembler类的代码:
package org.intan.pedigree.service;import java.util.ArrayList;import java.util.Collection;import org.intan.pedigree.form.SecurityRoleEntity;import org.intan.pedigree.form.UserEntity;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.authority.GrantedAuthorityImpl;import org.springframework.security.core.userdetails.User;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;@Service('assembler')public class Assembler {@Transactional(readOnly = true)User buildUserFromUserEntity(UserEntity userEntity) {String username = userEntity.getUsername();String password = userEntity.getPassword();boolean enabled = userEntity.getActive();boolean accountNonExpired = userEntity.getActive();boolean credentialsNonExpired = userEntity.getActive();boolean accountNonLocked = userEntity.getActive();Collection authorities = new ArrayList();for (SecurityRoleEntity role : userEntity.getSecurityRoleCollection()) {authorities.add(new GrantedAuthorityImpl(role.getName()));}User user = new User(username, password, enabled,accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);return user;}}
现在剩下要做的唯一事情就是定义applicationContext-Security.xml中必需的内容。 为此,创建一个具有以下内容的名为“ applicationContext-Security.xml”的新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:xsi='http://www.w3.org/2001/XMLSchema-instance'xmlns:context='http://www.springframework.org/schema/context'xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd'><beans:bean id='userDetailsService' class='org.intan.pedigree.service.UserDetailsServiceImpl'></beans:bean><context:component-scan base-package='org.intan.pedigree' /><http auto-config='true'><intercept-url pattern='/admin/**' access='ROLE_ADMIN' /><intercept-url pattern='/user/**' access='ROLE_REGISTERED_USER' /><intercept-url pattern='/kennel/**' access='ROLE_KENNEL_OWNER' /><!-- <security:intercept-url pattern='/login.jsp' access='IS_AUTHENTICATED_ANONYMOUSLY' /> --></http><beans:bean id='daoAuthenticationProvider'class='org.springframework.security.authentication.dao.DaoAuthenticationProvider'><beans:property name='userDetailsService' ref='userDetailsService' /></beans:bean><beans:bean id='authenticationManager'class='org.springframework.security.authentication.ProviderManager'><beans:property name='providers'><beans:list><beans:ref local='daoAuthenticationProvider' /></beans:list></beans:property></beans:bean><authentication-manager><authentication-provider user-service-ref='userDetailsService'><password-encoder hash='plaintext' /></authentication-provider></authentication-manager></beans:beans>
在您的web.xml中放入以下代码,以加载applicationContext-security.xml文件。
<context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/applicationContext-hibernate.xml/WEB-INF/applicationContext-security.xml</param-value></context-param>
最后,请原谅任何输入错误等,因为此代码只是从我完成的个人工作中复制和粘贴的内容,如果某些操作无效,请提出问题,我们将非常乐意为您提供帮助。
参考: Spring 3,Spring Security在我们的JCG合作伙伴 Ioannis Dadis的Giannisapi博客中使用Hibernate实现了自定义UserDetails 。
翻译自: https://www.javacodegeeks.com/2012/08/spring-security-implementing-custom.html
实现userdetails