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虽然默认提供了一个登陆页面,但是这个页面实在太简陋了,只有在快速演示时才有可能它做系统的登陆页面,实际开发时无论是从美观还是实用性角度考虑,我 ...
随机推荐
- KVM学习
获取镜像目前大小 # qemu-img info debian.img 添加额外的10G空间到镜像中 # qemu-img resize -f raw debian.img +10GB 注意:并不是所 ...
- 使用kibana给不同的用户创建不同的space
Elastic安全机制 在很多的情况下,出于安全的原因,我们需要对不同的Kibana用户分配不同的用户权限,这样使得他们之间不能互相访问彼此的资源,同 时他们也应该对不同的索引拥有不同的权限,比如读, ...
- java设计模式单例模式
创建型模式: – 单例模式.工厂模式.抽象工厂模式.建造者模式.原型模式. • 结构型模式: – 适配器模式.桥接模式.装饰模式.组合模式.外观模式.享元模式.代理模 式. • 行为型模式: – 模版 ...
- Java基础之UDP协议和TCP协议简介及简单案例的实现
写在前面的废话:马上要找工作了,做了一年的.net ,到要找工作了发现没几个大公司招聘.net工程师,真是坑爹呀.哎,java就java吧,咱从头开始学呗,啥也不说了,玩命撸吧,我真可怜啊. 摘要: ...
- Python中的函数(高级使用)
一.将函数作为变量去使用 在Python中函数也是一种对象,是一种名为function的对象,所以可以将函数赋值给变量,类似整数.浮点数.列表.元组.字典赋值给变量. 我们编写如下程序: #codin ...
- python调用腾讯云短信接口
目录 python调用腾讯云短信接口 账号注册 python中封装腾讯云短信接口 python调用腾讯云短信接口 账号注册 去腾讯云官网注册一个腾讯云账号,通过实名认证 然后开通短信服务,创建短信应用 ...
- SpringBoot嵌入式Tomcat的自动配置原理
在读本篇文章之前如果你读过这篇文章SpringBoot自动装配原理解析应该会更加轻松 准备工作 我们知道SpringBoot的自动装配的秘密在org.springframework.boot.auto ...
- Promise 封装 ajax
Promise 封装ajax 成链式结构: var url = 'http'; function(method, url) { return new Promise(function(res, ret ...
- 高性能TcpServer(Java) - Netty
源码下载 -> 提取码 QQ:505645074 Netty 是一个高性能.异步事件驱动的 NIO 框架,它提供了对 TCP.UDP 和文件传输的支持,作为一个异步 NIO 框架,Netty ...
- bokeh 中 ValueError: Unrecognized range input: 解决方法
bokeh_data.index =bokeh_data.index.astype(np.str) 将其转换为字符型