Spring MVC 项目搭建 -5- spring security 使用数据库进行验证
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 使用数据库进行验证的更多相关文章
- Spring MVC 项目搭建 -6- spring security 使用自定义Filter实现验证扩展资源验证,使用数据库进行配置
Spring MVC 项目搭建 -6- spring security使用自定义Filter实现验证扩展url验证,使用数据库进行配置 实现的主要流程 1.创建一个Filter 继承 Abstract ...
- Spring MVC 项目搭建 -3- 快速 添加 spring security
Spring MVC 项目搭建 -3- 快速 添加 spring security 1.添加 spring-sample-security.xml <!-- 简单的安全检验实现 --> & ...
- Spring MVC 项目搭建 -4- spring security-添加自定义登录页面
Spring MVC 项目搭建 -4- spring security-添加自定义登录页面 修改配置文件 <!--spring-sample-security.xml--> <!-- ...
- Spring MVC 项目搭建 -2- 添加service ,dao,junit
Spring MVC 项目搭建 -2- 添加service ,dao,junit 1.dao public class Hero { private String name; public Strin ...
- Spring MVC 项目搭建 -1- 创建项目
Spring MVC 项目搭建 -1- 创建项目 1.创建 Dynamic Web project (SpringDemo),添加相关jar包 2.创建一个简单的controller类 package ...
- IDEA 创建Spring MVC项目搭建
概述 IntelliJ IDEA是一款更加集成智能的开发工具,相对Myeclipse开发而言,使用起来相对更加的方便:初步手动使用IDEA搭建Spring MVC项目,现将操作流程整理记录如下. 环境 ...
- 简单Spring MVC项目搭建
1.新建Project 开发环境我使用的是IDEA,其实使用什么都是大同小异的,关键是自己用的顺手. 首先,左上角File→New→Project.在Project页面选择Maven,然后勾上图中所示 ...
- Java Spring MVC项目搭建(二)——项目配置
1.站点配置文件web.xml 每一个Spring MVC 项目都必须有一个站点配置文件web.xml,他的主要功能吗....有一位大哥已经整理的很好,我借来了,大家看看: 引用博客地址: http: ...
- Java Spring MVC项目搭建(一)——Spring MVC框架集成
1.Java JDK及Tomcat安装 我这里安装的是JDK 1.8 及 Tomcat 8,安装步骤详见:http://www.cnblogs.com/eczhou/p/6285248.html 2. ...
随机推荐
- spring boot入门(一)自己动手搭建spring boot
spring boot官方文档 http://docs.spring.io/spring-boot/docs/1.2.3.RELEASE/reference/html/index.html 此篇文章 ...
- 传感器系列之4.12GPS定位传感器
4.12 GPS定位实验 一.实验目的 了解GPS的基本概念 了解NMEA-0183格式数据串的组成和关于GPS的常用语句 GPS的数据串解析 二.实验材料 具有串口通讯的电脑一台 ADS1.2开发环 ...
- 使用Spring MVC构建REST风格WEB应用
转自:http://fancy888.iteye.com/blog/1629120 对于运行在网络上的MIS系统而言,处理数据的是整个系统的主要任务,翻开程序我们可以看到,80%以上的代码都在处理数据 ...
- web前端面试题记录
记录了2017年5月下旬刚毕业时面试的经典面试题 布局方面 1. 响应式布局,左侧栏目固定,右侧内容随着屏幕宽度变化而变化(高频) flex布局 position布局 css3计算宽度 float布局 ...
- opencv基础到进阶(2)
本文为系列文章的第2篇,主要讲解对图像的像素的操作方法. 2.1存取像素值 为了存取矩阵元素,需要指定元素所在的行和列,程序会返回相应的元素.单通道图像返回单个数值,多通道图像,返回的则是一组向量(V ...
- Error getting nested result map values for 'company'. Cause: java.sql.SQLException: Invalid value for getInt() - 'NFHK188'
我今天遇到一个我不解的问题,是mybatis多对一关系查询出问题了,但是我自己还是解决了,在网上也查过那个错误,可是找不到我想要的.不知道你们遇到过没有,我接下来分享给大家.希望我这个第一篇博客能帮助 ...
- OpenGL教程(2)——第一个窗口
OpenGL环境终于配置好了,现在我们可以开始学习OpenGL了. 首先,创建一个.cpp文件,然后打上几行#include指令: #include <iostream> using st ...
- javacpp-opencv图像处理之1:实时视频添加文字水印并截取视频图像保存成图片,实现文字水印的字体、位置、大小、粗度、翻转、平滑等操作
欢迎大家积极开心的加入讨论群 群号:371249677 (点击这里进群) javaCV图像处理系列: javaCV图像处理之1:实时视频添加文字水印并截取视频图像保存成图片,实现文字水印的字体.位置. ...
- Qt自定义标签按钮
当你接触到Qt时,你会为它极为方便的跨平台方面感到吃惊,从而想尝试着使用Qt.渐渐地你会发现Qt自带的一些控件不能满足自己的需要,此时就需要我们自己定义一个属于自己的控件.总所周知,标签的风格设置类比 ...
- thphp5.0学习笔记(一)
1.目录结构: 其中thinkphp子目录是框架核心目录 thinkphp结构: 2.入口文件 默认自带的入口文件位于public/index.php 应用目录为application,其结构: in ...