Spring MVC 项目搭建 -5- spring security 使用数据库进行验证

1.创建数据表格(这里使用的是mysql)

CREATE TABLE security_role (
  id int NOT NULL auto_increment,
  name varchar(50) DEFAULT NULL,
  description varchar(200) DEFAULT NULL,
  PRIMARY KEY (id)
) ;

CREATE TABLE security_user (
  id int NOT NULL auto_increment,
  username varchar(50) DEFAULT NULL,
  password varchar(50) DEFAULT NULL,
  status int DEFAULT NULL,
  salt VARCHAR(45) NULL,
  description varchar(200) DEFAULT NULL,
  PRIMARY KEY (id)
) ;

CREATE TABLE security_user_role (
  user_id int not NULL,
  role_id int not NULL,
  PRIMARY KEY (user_id,role_id),
  CONSTRAINT security_user_role_ibfk_1 FOREIGN KEY (user_id) REFERENCES security_user (id) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT security_user_role_ibfk_2 FOREIGN KEY (role_id) REFERENCES security_role (id) ON DELETE CASCADE ON UPDATE CASCADE
) ;

INSERT INTO security_role (name,description) VALUES ( 'ROLE_ADMIN', 'admin');
INSERT INTO security_role (name,description) VALUES ( 'ROLE_DEV', 'developer');
INSERT INTO security_role (name,description) VALUES ( 'ROLE_TEST', 'tester');

INSERT INTO security_user  (username,password,status,description) VALUES ('admin', 'admin', '1', 'admin');
INSERT INTO security_user  (username,password,status,description) VALUES( 'dev', 'dev', '1', 'developer');
INSERT INTO security_user  (username,password,status,description) VALUES ('test', 'test', '1', 'tester');

INSERT INTO security_user_role (user_id,role_id) VALUES ('1', '1');
INSERT INTO security_user_role (user_id,role_id) VALUES ('1', '2');
INSERT INTO security_user_role (user_id,role_id) VALUES ('1', '3');
INSERT INTO security_user_role (user_id,role_id) VALUES ('2', '2');
INSERT INTO security_user_role (user_id,role_id) VALUES ('3', '3');

2.DAO && VO

//省略get,set方法
public class SecurityRole {
    private int id;
    private String name;
    private String description;
}

public class SecurityUser{
    private int id ;
    private String username;
    private String password;
    private int status;
    private String description;
    private String salt;
    public SecurityUser(){

    }
    public SecurityUser(String username,String password,int status,String description,String salt){
        this.username = username;
        this.password = password;
        this.status = status;
        this.description = description;
        this.salt = salt;
    }
}

public interface ISecurityUserDao {
    /**
     * 根据用户名修改密码
     */
    public int changePassword(String username,String password);
    /**
     * 根据用户名寻找用户
     */
    public SecurityUser findByName(String username) throws SQLException;
    /**
     * 根据用户名获取用户角色
     */
    public Collection<GrantedAuthority> loadUserAuthorityByName(String username);
    /**
     * 根据用户名获取权限列表
     */
    public List<String> loadUserAuthorities(String username);
    /**
     * 获取所有用户
     */
    public List<SecurityUser> findAllUser();
    /**
     * 添加用户
     */
    public int addUser(SecurityUser user);
    /**
     * 添加用户
     */
    public int updateUser(SecurityUser user);
}

@Repository
/**
 * 继承 NamedParameterJdbcDaoSupport 需要注入dataSource属性
 */
public class SecurityUserDao  extends NamedParameterJdbcDaoSupport implements ISecurityUserDao{
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    public void setParentDataSource(
            @Qualifier("dataSource") DataSource dataSource) {
        super.setDataSource(dataSource);
    }
    private static final Log log = LogFactory.getLog(SecurityUserDao.class);
    private final String CHANGE_PASSWORD_SQL = "UPDATE security_user set password = ? WHERE username = ?";
    //private final String GET_USER_LIST = "select * from security_user where username=?";
    public int changePassword(String username,String password){
        return jdbcTemplate.update( CHANGE_PASSWORD_SQL, password, username);
    }
    public SecurityUser findByName(String username) throws SQLException{
        String sql = "select * from security_user where username='" + username + "'";
        RowMapper<SecurityUser> mapper = new RowMapper<SecurityUser>() {
            public SecurityUser mapRow(ResultSet rs, int rowNum) throws SQLException {
                SecurityUser user = new SecurityUser();
                user.setId((int) rs.getLong("id"));
                user.setUsername(rs.getString("username"));
                user.setPassword(rs.getString("password"));
                user.setStatus(rs.getInt("status"));
                user.setDescription(rs.getString("description"));
                user.setSalt(rs.getString("salt"));
                return user;
            }
        };
        SecurityUser user = jdbcTemplate.queryForObject(sql, mapper);
        return user;
    }

    // 通过用户名获得权限集合
    public Collection<GrantedAuthority> loadUserAuthorityByName(String username) {
        try{
            List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();

            List<String> authsList = loadUserAuthorities(username);

            for(String roleName:authsList){
                GrantedAuthorityImpl authority = new GrantedAuthorityImpl(roleName);
                auths.add(authority);
            }
            return auths;
        }catch(RuntimeException re){
            log.error("" + re);
            throw re;
        }
    }

    // 获取权限列表
    public List<String> loadUserAuthorities(String username) {
        try {
            String sql = "select r.name as authority "
                    + "from security_user u join security_user_role ur on u.id= ur.user_id "
                    + "join security_role r on r.id= ur.role_id " + "where u.username='"
                    + username + "'";
            List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
            List<String> roles = new ArrayList<String>();
            for (Map<String, Object> map : list) {
                roles.add((String) map.get("authority"));
            }
            return roles;
        } catch (RuntimeException re) {
            log.error("find by authorities by username failed." + re);
            throw re;
        }
    }
    public List<SecurityUser> findAllUser(){
        String sql = "select * from security_user";
        RowMapper<SecurityUser> mapper = new RowMapper<SecurityUser>() {
            public SecurityUser mapRow(ResultSet rs, int rowNum) throws SQLException {
                SecurityUser user = new SecurityUser();
                user.setId((int) rs.getLong("id"));
                user.setUsername(rs.getString("username"));
                user.setPassword(rs.getString("password"));
                user.setStatus(rs.getInt("status"));
                user.setDescription(rs.getString("description"));
                user.setSalt(rs.getString("salt"));
                return user;
            }
        };

        List<SecurityUser> user = jdbcTemplate.query(sql, mapper);
        return user;
    }
    private final String INSERT_USER_SQL =
            "INSERT INTO security_user (username,password,status,description,salt) " +
            "VALUES(:username,:password,:status,:description,:salt)";
    @Override
    public int addUser(SecurityUser user) {
        return this.getNamedParameterJdbcTemplate().update(INSERT_USER_SQL,
                new BeanPropertySqlParameterSource(user));
    }

    private final String UPDATE_USER_SQL =
            "UPDATE security_user set status=:status,"+
            "description=:description,salt=:salt " +
            "WHERE username =:username";
    @Override
    public int updateUser(SecurityUser user) {
        return this.getNamedParameterJdbcTemplate().update(UPDATE_USER_SQL,
                new BeanPropertySqlParameterSource(user));
    }
}

3.UserDetailsService的编写

public interface IAppUserDetailsService extends UserDetailsService{
    /**
     * 根据用户名修改密码
     */
    public boolean changePasswordByUserName(String userName, String password);
    /**
     * 根据用户名 加密数据库内原始密码
     * 只用于手动修改了数据库密码进行加密
     */
    public boolean securityPassword(String userName);
    /**
     * 创建新用户
     */
    public boolean createUser(SecurityUser user);
    /**
     * 获取用户列表
     */
    public List<SecurityUser> getUserList();
    /**
     * 修改用户信息
     */
    public boolean updateUser(SecurityUser user);
}

//用于获取用户名密码
@SuppressWarnings("deprecation")
public class AppUserDetailService implements IAppUserDetailsService {
    private static final Log log = LogFactory.getLog(AppUserDetailService.class);
    @Autowired
    private SecurityUserDao securityUserDao;
    @Autowired
    private SaltSource saltSource;
    @Autowired
    private PasswordEncoder passwordEncoder;
    /**
     * UserDetailsService 的 核心方法
     */
    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException, DataAccessException {
        System.out.println("username is :" + username);
        SecurityUser user = null;
        try {
            user = this.securityUserDao.findByName(username);
            System.out.println(user);
        } catch (SQLException e) {
            throw new UsernameNotFoundException("用户不存在");
        }
        // 获得用户权限
        Collection<GrantedAuthority> auths = securityUserDao
                .loadUserAuthorityByName(username);
        boolean enables = true;
        // 账户过期否
        boolean accountNonExpired = true;
        // 证书过期否
        boolean credentialsNonExpired = true;
        // 账户锁定否
        boolean accountNonLocked = true;
        // 封装成spring security的user
        AppUser userdetail = new AppUser(username, user.getPassword(), enables,
                accountNonExpired, credentialsNonExpired, accountNonLocked,
                auths,user.getSalt());
        for (GrantedAuthority s : auths) {
            s.getAuthority();
        }
        System.out.println(auths);
        System.out.println(userdetail);
        return userdetail;
    }
    /**
     * 修改用户密码并加密
     */
    @Override
    public boolean changePasswordByUserName(String userName, String password){
        UserDetails userdetail = loadUserByUsername(userName);
        log.info("salt:"+ saltSource.getSalt(userdetail));
        String pw = passwordEncoder.encodePassword(password, saltSource.getSalt(userdetail));
        int result  = securityUserDao.changePassword(userName,pw);
        return result > 0;
    }
    /**
     * 将指定用户没有加密的密码加密
     */
    @Override
    public boolean securityPassword(String userName) {
        UserDetails userdetail = loadUserByUsername(userName);
        String pw = userdetail.getPassword();
        return changePasswordByUserName(userName,pw);
    }

    @Override
    public boolean createUser(SecurityUser user) {
        boolean success = true;
        int i = securityUserDao.addUser(user);
        if(i>0){
            success = securityPassword(user.getUsername());
        }else{
            success = false;
        }
        return success;
    }
    @Override
    public List<SecurityUser> getUserList() {

        List<SecurityUser> result = securityUserDao.findAllUser();
        return result;
    }
    @Override
    public boolean updateUser(SecurityUser user) {
        System.out.println(user.getDescription());
        return securityUserDao.updateUser(user)>0;
    }
}

4.修改security配置(spring-sample-security.xml)

  • 添加注入配置
  • 修改拦截配置
  • 引入passwordEncoder,saltSource实现密码的加密
  • 引入appUserDetailService
  • 修改authenticationManager 引用 appUserDetailService
<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.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">
    <!--配置  security 管理 控制器-->
    <context:component-scan base-package="security" />
    <context:component-scan base-package="security.service.impl" />
    <!-- 去除不需要拦截的url -->
    <http pattern="/libs/**" security="none"/>
    <http pattern="/login.html" security="none" />
    <http pattern="/resources/**" security="none" />
    <!-- 配置一层拦截,需要输入正确用户名密码才能访问网站 -->
    <http auto-config="true" use-expressions="true" >
        <!-- 拦截所有不是ROLE_USER的请求  -->
        <intercept-url pattern="/*" access="hasAnyRole('ROLE_ADMIN','ROLE_DEV','ROLE_TEST')" />
        <!-- 登录配置 -->
        <form-login login-page="/login.html"
            default-target-url="/test/mytest/loginSuccess"
            authentication-failure-url="/test/mytest/loginFaild"/>
        <logout invalidate-session="true"
            logout-success-url="/"
            logout-url="/j_spring_security_logout"/>
    </http>
    <!--默认拦截器  -->
    <authentication-manager alias="authenticationManager">
    <!--验证配置,认证管理器,实现用户认证的入口,主要实现UserDetailsService接口即可 -->
    <authentication-provider user-service-ref="appUserDetailService">
           <password-encoder ref="passwordEncoder">
                <salt-source ref="saltSource"/>
           </password-encoder>
       </authentication-provider>
    </authentication-manager>
    <!--在这个类中,你就可以从数据库中读入用户的密码,角色信息,是否锁定,账号是否过期等 -->
    <beans:bean id="appUserDetailService" class="security.service.impl.AppUserDetailService" />
    <!--加密密码  -->
    <beans:bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" />
    <!--为密码添加 saltSource -->
    <beans:bean id="saltSource" class="org.springframework.security.authentication.dao.ReflectionSaltSource" >
        <beans:property name="userPropertyToUse" value="salt"/>
    </beans:bean>
</beans:beans> 

5.添加Junit Test方法 运行密码加密方法,将数据库的密码加密

package security;

import junit.framework.Assert;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import security.service.IAppUserDetailsService;
import security.vo.SecurityUser;

//基于junit4的测试框架
@RunWith(SpringJUnit4ClassRunner.class)
//启动spring容器
@ContextConfiguration(locations = {
    "classpath:applicationContext.xml",
    "file:WebContent/WEB-INF/spring-test-servlet.xml",
    "file:WebContent/WEB-INF/config/spring-sample-security.xml"
})
public class SecurityTest {
    @Autowired
    private IAppUserDetailsService userService;
    @Test
    public void securityPassword() {
        Assert.assertTrue(userService.securityPassword("admin"));
        Assert.assertTrue(userService.securityPassword("test"));
        Assert.assertTrue(userService.securityPassword("dev"));
    }
}

Spring MVC 项目搭建 -5- spring security 使用数据库进行验证的更多相关文章

  1. Spring MVC 项目搭建 -6- spring security 使用自定义Filter实现验证扩展资源验证,使用数据库进行配置

    Spring MVC 项目搭建 -6- spring security使用自定义Filter实现验证扩展url验证,使用数据库进行配置 实现的主要流程 1.创建一个Filter 继承 Abstract ...

  2. Spring MVC 项目搭建 -3- 快速 添加 spring security

    Spring MVC 项目搭建 -3- 快速 添加 spring security 1.添加 spring-sample-security.xml <!-- 简单的安全检验实现 --> & ...

  3. Spring MVC 项目搭建 -4- spring security-添加自定义登录页面

    Spring MVC 项目搭建 -4- spring security-添加自定义登录页面 修改配置文件 <!--spring-sample-security.xml--> <!-- ...

  4. Spring MVC 项目搭建 -2- 添加service ,dao,junit

    Spring MVC 项目搭建 -2- 添加service ,dao,junit 1.dao public class Hero { private String name; public Strin ...

  5. Spring MVC 项目搭建 -1- 创建项目

    Spring MVC 项目搭建 -1- 创建项目 1.创建 Dynamic Web project (SpringDemo),添加相关jar包 2.创建一个简单的controller类 package ...

  6. IDEA 创建Spring MVC项目搭建

    概述 IntelliJ IDEA是一款更加集成智能的开发工具,相对Myeclipse开发而言,使用起来相对更加的方便:初步手动使用IDEA搭建Spring MVC项目,现将操作流程整理记录如下. 环境 ...

  7. 简单Spring MVC项目搭建

    1.新建Project 开发环境我使用的是IDEA,其实使用什么都是大同小异的,关键是自己用的顺手. 首先,左上角File→New→Project.在Project页面选择Maven,然后勾上图中所示 ...

  8. Java Spring MVC项目搭建(二)——项目配置

    1.站点配置文件web.xml 每一个Spring MVC 项目都必须有一个站点配置文件web.xml,他的主要功能吗....有一位大哥已经整理的很好,我借来了,大家看看: 引用博客地址: http: ...

  9. Java Spring MVC项目搭建(一)——Spring MVC框架集成

    1.Java JDK及Tomcat安装 我这里安装的是JDK 1.8 及 Tomcat 8,安装步骤详见:http://www.cnblogs.com/eczhou/p/6285248.html 2. ...

随机推荐

  1. openMRS项目

    openMRS项目的背景:我们的世界继续遭受大规模的大流行,因为超过4000万人感染或死于艾滋病毒/艾滋病-大多数(高达95%)是在发展中国家.预防和治疗艾滋病毒/艾滋病这种规模需要有效的信息管理,这 ...

  2. WARN Session 0x0 for server null, unexpected error, closing socket connection and attempting reconnect (org.apache.zookeeper.ClientCnxn)

    [2017-05-19 13:32:14,933] INFO Waiting for keeper state SyncConnected (org.I0Itec.zkclient.ZkClient) ...

  3. qt添加资源文件方法

    File->new file->file and classes->Qt->qt resources->   add name   add->add prefix- ...

  4. .Net程序员学用Oracle系列(8):触发器、作业、序列、连接

    1.触发器 2.作业 2.1.作业调度功能和应用 2.2.通过 DBMS_JOB 来调度作业 3.序列 3.1.创建序列 3.2.使用序列 & 删除序列 4.连接 4.1.创建连接 4.2.使 ...

  5. [转]JAVA的动态代理机制及Spring的实现方式

    JAVA 代理实现 代理的实现分动态代理和静态代理,静态代理的实现是对已经生成了的JAVA类进行封装. 动态代理则是在运行时生成了相关代理累,在JAVA中生成动态代理一般有两种方式. JDK自带实现方 ...

  6. AngularJS语法基础及数据绑定——详解各种数据绑定指令、属性应用

    AngularJS简单易学,但是功能强大.特别是在构建单页面应用方面效果显著.而 数据绑定 可以说是他被广泛使用的最主要的优点.他舍弃了对DOM的操作方式,一切都由AngularJS来自动更新视图,我 ...

  7. 基于NIO的Netty网络框架

    Netty是一个高性能.异步事件驱动的NIO框架,它提供了对TCP.UDP和文件传输的支持,Netty的所有IO操作都是异步非阻塞的,通过Future-Listener机制,用户可以方便的主动获取或者 ...

  8. SQL SERVER 自动生成 MySQL 表结构及索引 的建表SQL

          SQL SERVER的表结构及索引转换为MySQL的表结构及索引,其实在很多第三方工具中有提供,比如navicat.sqlyog等,但是,在处理某些数据类型.默认值及索引转换的时候,总有些 ...

  9. thinkphp5.0学习笔记(二)

    本文为公司制作API接口后台的小结! 1.命名注意事项: 不要使用易混淆的名字,如index,index01... 我喜欢用拼音... 比如: public function zhuce(Reques ...

  10. 卷积神经网络的变种: PCANet

    前言:昨天和大家聊了聊卷积神经网络,今天给大家带来一篇论文:pca+cnn=pcanet.现在就让我带领大家来了解这篇文章吧. 论文:PCANet:A Simple Deep Learning Bas ...