Spring Security教程之加点密,加点盐(七)
一、概述
一般用数据库保存用户的密码都是经过加密,甚少使用明文。同时,加密方式一般采用不可逆的加密方法,如MD5。也要避免相同的密码在加密后有相同的密文,如admin用户的密码为admin,加密后变成ceb4f32325eda6142bd65215f4c0f371,加入另外一个用户user,他的密码也是admin,那么加密后两者的密码相同,假如黑客知晓了admin的账户与密码,一旦获取到整个存储密码的数据表,那么就可以推断出user的密码也是admin,从而造成损失。为了解决这个问题,在加密的同时,也需要加点盐,避免相同密码加密后有相同的密文。
二、自定义MyUsernamePasswordAuthenticationFilter
这个类可以继承UsernamePasswordAuthenticationFilter,然后重写attemptAuthentication方法,这个方法是登陆的入口方法。
package com.zmc.demo; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.util.StringUtils; /**
* @classname MyUsernamePasswordAuthenticationFilter
* @author ZMC
* @time 2017-1-13
*
*/
public class MyUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter { public static final String USERNAME = "j_username";
public static final String PASSWORD = "j_password";
/**
* @Description:用户登录验证方法入口
* @param :args
* @return
* @throws Exception
*/
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException { if (!request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: "
+ request.getMethod());
}
String username = this.obtainUsername(request);
String password = this.obtainPassword(request);
// 加密密码(根据“密码{用户名})进行加密
// String sh1Password = password + "{" + username + "}";
// PasswordEncoder passwordEncoder = new
// StandardPasswordEncoderForSha1();
// String result = passwordEncoder.encode(sh1Password);
// UserInfo userDetails = (UserInfo)
// userDetailsService.loadUserByUsername(username);
if (username == null) {
username = "";
} if (password == null) {
password = "";
} //使用MD5加密,使用username作为盐值
Md5PasswordEncoder encoder = new Md5PasswordEncoder();
password = encoder.encodePassword(password, username); username = username.trim(); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password); // Allow subclasses to set the "details" property
setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } /**
* @Description:获取密码
* @param :args
* @return
* @throws Exception
*/
@Override
protected String obtainPassword(HttpServletRequest request) {
// TODO Auto-generated method stub
Object obj = request.getParameter(PASSWORD);
return null == obj ? "" : obj.toString();
} /**
* @Description:获取用户名
* @param :args
* @return
* @throws Exception
*/
@Override
protected String obtainUsername(HttpServletRequest request) {
// TODO Auto-generated method stub
Object obj = request.getParameter(USERNAME);
return null == obj ? "" : obj.toString().trim().toLowerCase();
} }
上述的代码这样写其实和默认的UsernamePasswordAuthenticationFilter并没有什么区别,但是这里主要是学会将自定义的Filter加入到security中的FilterChain中去,实际上这个方法中,一般会直接验证用户输入的和通过用户名从数据库里面查到的用户的密码是否一致,如果不一致,就抛异常,否则继续向下执行。
三、配置MyUsernamePasswordAuthenticationFilter并将其加入到FilterChain中去
MyUsernamePasswordAuthenticationFilter有filterProcessesUrl属性为登陆的过滤的地址,authenticationManager为authentication-manager标签中配置的东西,authenticationSuccessHandler为验证成功后跳转的处理器,authenticationFailureHandler为验证失败的处理器。另外还要配置一个出登陆引导的处bean:LoginUrlAuthenticationEntryPoint
配置代码如下:
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd"> <http pattern="/login.jsp" security="none"></http>
<http auto-config="false" entry-point-ref="loginUrlAuthenticationEntryPoint">
<!-- <form-login login-page="/login.jsp" default-target-url="/index.jsp"
authentication-failure-url="/login.jsp?error=true" /> -->
<logout invalidate-session="true" logout-success-url="/login.jsp"
logout-url="/j_spring_security_logout" />
<custom-filter ref="myUsernamePasswordAuthenticationFilter" position="FORM_LOGIN_FILTER" />
<!-- 通过配置custom-filter来增加过滤器,before="FILTER_SECURITY_INTERCEPTOR"表示在SpringSecurity默认的过滤器之前执行。 -->
<custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR" />
</http>
<beans:bean id="loginUrlAuthenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl" value="/login.jsp" />
</beans:bean> <!-- 数据源 -->
<beans:bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<!-- 此为c3p0在spring中直接配置datasource c3p0是一个开源的JDBC连接池 -->
<beans:property name="driverClass" value="com.mysql.jdbc.Driver" />
<beans:property name="jdbcUrl"
value="jdbc:mysql://localhost:3306/springsecuritydemo?useUnicode=true&characterEncoding=UTF-8" />
<beans:property name="user" value="root" />
<beans:property name="password" value="" />
<beans:property name="maxPoolSize" value="50"></beans:property>
<beans:property name="minPoolSize" value="10"></beans:property>
<beans:property name="initialPoolSize" value="10"></beans:property>
<beans:property name="maxIdleTime" value="25000"></beans:property>
<beans:property name="acquireIncrement" value="1"></beans:property>
<beans:property name="acquireRetryAttempts" value="30"></beans:property>
<beans:property name="acquireRetryDelay" value="1000"></beans:property>
<beans:property name="testConnectionOnCheckin" value="true"></beans:property>
<beans:property name="idleConnectionTestPeriod" value="18000"></beans:property>
<beans:property name="checkoutTimeout" value="5000"></beans:property>
<beans:property name="automaticTestTable" value="t_c3p0"></beans:property>
</beans:bean> <beans:bean id="builder" class="com.zmc.demo.JdbcRequestMapBulider">
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="resourceQuery"
value="select re.res_string,r.name from role r,resc re,resc_role rr where
r.id=rr.role_id and re.id=rr.resc_id" />
</beans:bean> <beans:bean id="myUsernamePasswordAuthenticationFilter"
class="com.zmc.demo.MyUsernamePasswordAuthenticationFilter
">
<beans:property name="filterProcessesUrl" value="/j_spring_security_check" />
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="authenticationSuccessHandler"
ref="loginLogAuthenticationSuccessHandler" />
<beans:property name="authenticationFailureHandler"
ref="simpleUrlAuthenticationFailureHandler" />
</beans:bean> <beans:bean id="loginLogAuthenticationSuccessHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<beans:property name="targetUrlParameter" value="/index.jsp" />
</beans:bean> <beans:bean id="simpleUrlAuthenticationFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl" value="/login.jsp" />
</beans:bean> <!-- 认证过滤器 -->
<beans:bean id="filterSecurityInterceptor"
class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<!-- 用户拥有的权限 -->
<beans:property name="accessDecisionManager" ref="accessDecisionManager" />
<!-- 用户是否拥有所请求资源的权限 -->
<beans:property name="authenticationManager" ref="authenticationManager" />
<!-- 资源与权限对应关系 -->
<beans:property name="securityMetadataSource" ref="securityMetadataSource" />
</beans:bean> <!-- acl领域模型 -->
<beans:bean class="com.zmc.demo.MyAccessDecisionManager" id="accessDecisionManager">
</beans:bean>
<!-- -->
<authentication-manager alias="authenticationManager">
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="select username,password,status as enabled from user where username = ?"
authorities-by-username-query="select user.username,role.name from user,role,user_role
where user.id=user_role.user_id and
user_role.role_id=role.id and user.username=?" />
</authentication-provider>
</authentication-manager> <beans:bean id="securityMetadataSource"
class="com.zmc.demo.MyFilterInvocationSecurityMetadataSource">
<beans:property name="builder" ref="builder"></beans:property>
</beans:bean> </beans:beans>
其他的一些配置在教程五有详细的讲解。
四、结果
---------------------
作者:AirMario
来源:CSDN
原文:https://blog.csdn.net/AirMario/article/details/54411524
Spring Security教程之加点密,加点盐(七)的更多相关文章
- Spring Security教程(五):自定义过滤器从数据库从获取资源信息
在之前的几篇security教程中,资源和所对应的权限都是在xml中进行配置的,也就在http标签中配置intercept-url,试想要是配置的对象不多,那还好,但是平常实际开发中都往往是非常多的资 ...
- Spring Security教程(八):用户认证流程源码详解
本篇文章主要围绕下面几个问题来深入源码: 用户认证流程 认证结果如何在多个请求之间共享 获取认证用户信息 一.用户认证流程 上节中提到Spring Security核心就是一系列的过滤器链,当一个请求 ...
- Spring Security教程(三):自定义表结构
在上一篇博客中讲解了用Spring Security自带的默认数据库存储用户和权限的数据,但是Spring Security默认提供的表结构太过简单了,其实就算默认提供的表结构很复杂,也不一定能满足项 ...
- Spring Security教程(二):通过数据库获得用户权限信息
上一篇博客中,Spring Security教程(一):初识Spring Security,我把用户信息和权限信息放到了xml文件中,这是为了演示如何使用最小的配置就可以使用Spring Securi ...
- 临远的spring security教程
为啥选择Spring Security 欢迎阅读咱们写的Spring Security教程,咱们既不想写一个简单的入门教程,也不想翻译已有的国外教程.咱们这个教程就是建立在咱们自己做的OA的基础上,一 ...
- Spring Security 教程 大牛的教程
https://www.iteye.com/blog/elim-2247073 Spring Security 教程 Spring Security(20)——整合Cas Spring Securit ...
- Spring Security教程(三)
在上一篇博客中讲解了用Spring Security自带的默认数据库存储用户和权限的数据,但是Spring Security默认提供的表结构太过简单了,其实就算默认提供的表结构很复杂,也不一定能满足项 ...
- Spring Security教程(二)
上一篇博客中,Spring Security教程(一),我把用户信息和权限信息放到了xml文件中,这是为了演示如何使用最小的配置就可以使用Spring Security,而实际开发中,用户信息和权限信 ...
- Spring Security教程(二):自定义数据库查询
Spring Security教程(二):自定义数据库查询 Spring Security自带的默认数据库存储用户和权限的数据,但是Spring Security默认提供的表结构太过简单了,其实就 ...
- Spring Security教程系列(一)基础篇-2
第 4 章 自定义登陆页面 Spring Security虽然默认提供了一个登陆页面,但是这个页面实在太简陋了,只有在快速演示时才有可能它做系统的登陆页面,实际开发时无论是从美观还是实用性角度考虑,我 ...
随机推荐
- 微信小程序练习笔记(更新中。。。)
微信小程序练习笔记 微信小程序的练习笔记,用来整理思路的,文档持续更新中... 案例一:实现行的删除和增加操作 test.js // 当我们在特定方法中创建对象或者定义变量给与初始值的时候,它是局部 ...
- 关于plupload组件无法拍照上传的解决方案
关于plupload组件无法拍照上传的解决方案 其实是由于文件大小的问题 filters: { max_file_size: '2mb',//把这个调大些就可以了 前提是服务器支持 prevent_d ...
- js计算两经纬度之间的距离
js如下: // 方法定义 lat,lng function GetDistance( lat1, lng1, lat2, lng2){ var radLat1 = lat1*Math.PI / ...
- 浅聊几种主流Docker网络的实现原理
原文:https://mp.weixin.qq.com/s/Jdxct8qHrBUtkUq-hnxSRw 参考:https://blog.csdn.net/yarntime/article/detai ...
- spring根据beanName获取bean
spring根据beanName获取bean主要实现: org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean( ...
- 微服务架构 ------ DockerCompose从安装到项目部署
DockerCompose的目的:简化Docker的启动和停止流程,以及编排Docker启动服务与服务之间的关系 DockerCompose的安装:curl -L https://get.daoclo ...
- js中面向对象(创建对象的几种方式)
1.面向对象编程(OOP)的特点: 抽象:抓住核心问题 封装:只能通过对象来访问方法 继承:从已有的对象下继承出新的对象 多态:多对象的不同形态 注:本文引用于 http://www.cnblogs. ...
- maven 学习---Maven中央存储库
当你建立一个 Maven 的项目,Maven 会检查你的 pom.xml 文件,以确定哪些依赖下载. 首先,Maven 将从本地资源库获得 Maven 的本地资源库依赖资源, 如果没有找到,然后把它会 ...
- MySQL5.7 安装和配置环境变量
安装 1.下载安装包 官网地址:https://dev.mysql.com/downloads/mysql/ 2.选择 Custom,自定义 3.根据自己系统选择 x64还是x86,然后点击第一个箭头 ...
- Linux操作系统的打包/归档工具介绍
Linux操作系统的打包/归档工具介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.