技术交流群: 233513714

本文介绍的是RSA加密算法+Spring Security在SpringMVC中的集成使用。

Spring Security是什么?


引用:
  Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
  Spring Security以前叫做acegi,是后来才成为Spring的一个子项目,也是目前最为流行的一个安全权限管理框架,它与Spring紧密结合在一起。
  Spring Security关注的重点是在企业应用安全层为您提供服务,你将发现业务问题领域存在着各式各样的需求。银行系统跟电子商务应用就有很大的不同。电子商务系统与企业销售自动化工具又有很大不同。这些客户化需求让应用安全显得有趣,富有挑战性而且物有所值。Spring Security为基于J2EE的企业应用软件提供了一套全面的安全解决方案。

学习Spring Security的网址http://www.iteye.com/blogs/subjects/spingsecurity3inside。

Spring-Security 自带的加密算法有

- bcrypt
- plaintext
- sha
- sha-256
- md5
- md4
- {sha}
- {ssha}

由于md5加密算法,使用较为普遍,但是可以通过碰撞的方式破解,不采用。

 RSA是什么?

同RSA(Ron Rivest,Adi Shamir,Len Adleman三位天才的名字)一样,ECC(Elliptic Curves Cryptography,椭圆曲线密码编码学)也属于公开密钥算法。但是ECC算法在jdk1.5后加入支持,目前仅仅只能完成密钥的生成与解析。

  RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准。今天只有短的RSA钥匙才可能被强力方式解破。到2008年为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被解破的。但在分布式计算和量子计算机理论日趋成熟的今天,RSA加密安全性受到了挑战。RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。

RSA密钥长度随着保密级别提高,增加很快。下表列出了对同一安全级别所对应的密钥长度。

保密级别
对称密钥长度(bit)
RSA密钥长度(bit)
ECC密钥长度(bit)
保密年限
80
80
1024
160
2010
112
112
2048
224
2030
128
128
3072
256
2040
192
192
7680
384
2080
256
256
15360
512
2120

如何实现的RSA+Spring Security 在Spring MVC中的实现,直接上web.xml

 xml中的com.user.sec.MyHttpSessionEventPublisher
为自定义的org.springframework.security.web.session.HttpSessionEventPublisher  两者使用其一。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:web="http://java.sun.com/xml/ns/javaee" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" metadata-complete="false" version="2.5">
 <!--配置上下文参数,指定spring配置文件的位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring/applicationContext-*.xml</param-value>
</context-param>
<!--Spring Security 过滤器-->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--Spring 字符集过滤器 -->
<!--包含设置两个参数encoding和forceEncoding-->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>*</url-pattern>
</filter-mapping>
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>excludeSuffixs</param-name>
<param-value>js,css,jpg,gif</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>com.user.sec.MyHttpSessionEventPublisher</listener-class>
</listener>
<!-- <listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener> -->
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>WEB-INF/classes/properties/log4j.properties</param-value>
</context-param>
<context-param>
<param-name>log4jRefreshInterval</param-name>
<param-value>60000</param-value>
</context-param>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring/applicationContext-springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<servlet-name>springmvc</servlet-name>
</filter-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<error-page>
<error-code>500</error-code>
<location>/500.html</location>
</error-page>
</web-app>

applicationContext-security.xml

  Spring Security采用就近原则,有多个约束时,从上至下只要找到第一条满足就返回,因此因该将最严格的约束放在最前面,而将最宽松的约束放在最后面.auto-config属性可以让spring security为我们自动配置几种常用的权限控制机制,包括form,anonymous, rememberMe等。当然你也可以手工配置。例如:<http auto-config="true">

对于拦截pattern的设置,具体如下:

/  所有带/的请求

/* 代表这个域下面的请求  例如:/user/xxx 这种会被拦截  但是不会拦截 /user/xxx/xxx

/** 代表跨域请求  例如:/user/xxx  和 /user/xxx/xxx都会被拦截

<?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.2.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd"> <global-method-security secured-annotations="enabled" />
  
<!--配置不过滤的资源,包括登陆请求,静态资源访问,注册页面,获取登陆注册验证码,当然也包括此篇文章所涉及从后台获取的公钥接口-->
   <http pattern="/resources/**" security="none" />
<http pattern="/login.html" security="none" />
<http pattern="/register.html" security="none" />
<http pattern="/admin/user/getPairKey" security="none"

<http use-expressions="true" auto-config="true">
<!--允许登录用户操作 -->
<intercept-url pattern="/pages/**" access="permitAll" />
<intercept-url pattern="/**" access="isAuthenticated()" />
<!--所有用户均可使用 -->
<!-- <intercept-url pattern="/**" access="permitAll" /> -->
<!-- 允许匿名用户访问 -->
<!-- <intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY" /> -->
<!-- <intercept-url pattern="/" access="ROLE_ANONYMOUS" /> -->
<!-- 验证失败页面 -->
<form-login login-page="/login.html"
authentication-failure-url="/login.html?error=true"
login-processing-url="/j_spring_security_check" default-target-url="/index.html"
always-use-default-target="true" />
<!-- 注销页面 -->
<logout logout-success-url="/login.html" />
<!-- 记住登陆 -->
<remember-me key="mpbuser" user-service-ref="userDetailService" />
<session-management invalid-session-url="/login.html"
session-authentication-error-url="/login.html">
<concurrency-control max-sessions="100"
error-if-maximum-exceeded="false" expired-url="/login.html" />
</session-management> <custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="myDefineFilter" />
<!-- 验证权限不足处理类 -->
<access-denied-handler ref="accessDeniedHandler" />
<http-basic />
</http> <beans:bean id="encoder"
class="org.springframework.security.crypto.password.StandardPasswordEncoder" />
<beans:bean id="RSAEncoder"
class="com.common.component.util.RSAPasswordEncoder" />
<authentication-manager alias="authenticationManager"
erase-credentials="false">
<authentication-provider user-service-ref="userDetailService">
<password-encoder ref="RSAEncoder" />
</authentication-provider>
<!--自定义Provider -->
<!-- <authentication-provider ref="myAuthenticationProvider"> </authentication-provider> -->
</authentication-manager>

<beans:bean id="myDefineFilter"
class="com.user.sec.MyFilterSecurityInterceptor">
<beans:property name="authenticationManager" ref="authenticationManager" /> <!-- <beans:property name="accessDecisionManager" ref="accessDecisionManager"
/> --> <beans:property name="securityMetadataSource" ref="databaseDefinitionSource" /> <beans:property name="accessDecisionManager" ref="myAccessDecisionManager" /> </beans:bean> <!-- <beans:bean id="myAuthenticationProvider" class="crowdfunding.user.sec.MyAuthenticationProvider"/> -->
<beans:bean id="databaseDefinitionSource"
class="com.user.sec.DefinitionSourceFactoryBean">
<beans:constructor-arg ref="resourceDetailService" />
<!-- <beans:constructor-arg ref="userDetailService" /> -->
</beans:bean> <beans:bean id="myAccessDecisionManager"
class="com.user.sec.MyAccessDecisionManager">
</beans:bean> <beans:bean id="accessDeniedHandler" class="com.user.sec.MyAccessDeniedHandler" /> </beans:beans>

RSAPasswordEncoder.Java

package com.common.component.util;

import java.net.URLDecoder;

import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.encoding.PasswordEncoder; import Decoder.BASE64Decoder;
import Decoder.BASE64Encoder;
import com.common.component.util.MpbSecureRSAUtil; /*******************************************************
* Description:自定义RSA处理类
* 如需增加Spring Security 另外的加密方式,重新定义此类<br/>
********************************************************/
public class RSAPasswordEncoder implements PasswordEncoder { /*****************************************
* Description:明文加密 <br/>
* @return
* @param rawPass
* 密码
******************************************/
public String encodePassword(String rawPass, Object salt) { String encoder = "";
try {
encoder = MpbSecureRSAUtil.decryptString(rawPass);
} catch (Exception e) { e.printStackTrace();
}
return encoder;
} /*****************************************
* Description:验证密码是否有效主要是此方法的使用<br/>
*
* @return boolean
******************************************/
public boolean isPasswordValid(String encPass, String rawPass, Object salt) { if ( !MpbStringUtil.isNotBlank(encPass) || encPass.length() == 0) {
return false;
}
String decPsw = MpbSecureRSAUtil.decryptString(encPass);
String inpdecPsw = MpbSecureRSAUtil.decryptStringByJs(rawPass);
try {
decPsw = URLDecoder.decode(decPsw, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
return false;
}
return inpdecPsw.equals(decPsw);
} /*****************************************
* Description:私钥解密 <br/>
*
* @return
******************************************/
public String decryptPassword(String rawPass, Object salt) { String encoder = "";
try {
encoder = MpbSecureRSAUtil.decryptString(rawPass);
} catch (Exception e) { e.printStackTrace();
}
return encoder;
} /*****************************************
* Description:Base64解密 <br/>
* @param key
* @return
* @throws Exception
******************************************/
public static byte[] decoderBase64(String key) throws Exception {
return (new BASE64Decoder()).decodeBuffer(key);
} /*****************************************
* Description:Base64加密 <br/>
*
* @param key
* @return
* @throws Exception
******************************************/
public static String encoderBase64(byte[] key) throws Exception {
return (new BASE64Encoder()).encodeBuffer(key);
} }

login.html

<script type="text/javascript" src="resources/js/RSA/security.js"></script>
    function mysubmit() {
if ($("input[name='_spring_security_remember_me']").attr("checked") == "checked") {
//如果记住用户名和密码框被选中则执行remenber()方法
remember();
}else{
//如果未选中则清空cookie
$.mpbSetCookie("EBS_ISCHECKED", "");
}
//从后台获取公钥并加密,将加密后的密文传输到服务器处理
$.mpbPost(
"/admin/user/getPairKey",
{
"_method" : "GET"
},
function(data) { var modulus = data['modul'];
var exponent = data['exponent'];
var key = RSAUtils.getKeyPair(exponent, '', modulus);
var pwd = $("#psw").val();
pwd = encodeURIComponent(pwd);
pwd = RSAUtils.encryptedString(key, pwd);
//$("#psw").attr("value",pwd);
$("input[name='j_password']").val(pwd);
$("#myform").submit();
}); }

Controler.Java

@ResponseBody
@RequestMapping(value = "/getPairKey", method = RequestMethod.GET)
public Map<?,?> getKey() throws Exception {
RSAPublicKey publicKey = MpbSecureRSAUtil.getDefaultPublicKey(); Map<String, String> key = new HashMap<String,String>(); key.put("modul",
new String(Hex.encodeHex(publicKey.getModulus().toByteArray())));
key.put("exponent",
new String(Hex.encodeHex(publicKey.getPublicExponent()
.toByteArray()))); return key;
}

文件地址:

http://files.cnblogs.com/files/Sonet-life/security.js

http://files.cnblogs.com/files/Sonet-life/MpbSecureRSAUtil.rar

整个加密的思路:

1、项目在启动时就检查是否生成密钥对文件,没有就强制生成新的,记住利用RSA注册的用户在数据库保存的是加密后的密文,RSA密钥对文件要保证一致性,如果密钥对文件生成了新的,而且你没备份之前的密钥对文件,将会造成不可挽回的后果。最好的方法,通过对MpbSecureRSAUtil中密钥对文件的生成路径设置成硬盘下的,不要放到Tomcat服务器中,否则每次你删除项目的时候,或者重新部署都会造成密钥对文件的重新生成。或者每次都用旧的替换新生成的,保持可用性。

2、前台请求服务器的公钥,传输到前台,因为公钥是公开的,使用公钥在前台加密用户登录注册或者其他保密的信息,将公钥加密的密文传输到服务器。服务器通过与公钥对应的私钥,解密数据库的密文和传输过来的密文,将解密后的字符相比较,再将确认信息返回到前台,进行下一步的操作。

SpringMVC集成RSA加密算法的更多相关文章

  1. RSA加密算法及其与SpringMVC集成

    如有不足,敬请各位提出批评,定会改正.THX! 本文介绍的是RSA加密算法+Spring Security在SpringMVC中的集成使用. Spring Security是什么? 引用: Sprin ...

  2. .net(c#)版RSA加密算法,拿走不谢

    今天有同学对接一个支付平台,涉及到RSA的签名和验签.由于对方是java的sdk,翻成c#语言时,搞了半天也没搞定.网上搜的东西都是各种copy还不解决问题. 碰巧,我之前对接过连连银通的网银支付和代 ...

  3. RSA加密算法的简单案例

    RSA加密算法是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击. 那关于RSA加密算法有哪些应用呢?以下举一个数据库身份验证的案例. 在使用数据集进行身份认证时,密码存在数据 ...

  4. RSA加密算法的java实现

    package rsa; import java.security.*;import java.security.interfaces.*;import javax.crypto.*; public ...

  5. 用实例讲解RSA加密算法(精)

    RSA是第一个比较完善的公开密钥算法,它既能用于加密,也能用于数字签名.RSA以它的三个发明者Ron Rivest, Adi Shamir, Leonard Adleman的名字首字母命名,这个算法经 ...

  6. 关于RSA加密算法的长度限制问题

    RSA是常用的非对称加密算法.近来有学生在项目中使用System.Security类库中的RSA加密算法时,出现了“不正确的长度”,这实际上是因为待加密的数据超长所致..net Framework中提 ...

  7. RSA加密算法的加密与解密

    转发原文链接:RSA加密算法加密与解密过程解析 1.加密算法概述 加密算法根据内容是否可以还原分为可逆加密和非可逆加密. 可逆加密根据其加密解密是否使用的同一个密钥而可以分为对称加密和非对称加密. 所 ...

  8. 【python网络编程】使用rsa加密算法模块模拟登录新浪微博

    一.基础知识 http://blog.csdn.net/pi9nc/article/details/9734437 二.模拟登录 因为上学期参加了一个大数据比赛,需要抓取数据,所以就想着写个爬虫抓取新 ...

  9. 轻松学习RSA加密算法原理

    转自:http://blog.csdn.net/sunmenggmail/article/details/11994013 http://blog.csdn.net/q376420785/articl ...

随机推荐

  1. 《spring技术内幕》读书笔记(1)——什么是POJO模式

    今天在看<spring技术内幕>,第一章中多次提到了使用POJO来完成开发,就百度了一下,在此保留 1.     什么是POJO POJO的名称有多种,pure old java obje ...

  2. python JSON性能测试与simplejson对比

    简单测试了一下,如果用JSON,也就是python2.6以上自带的json处理库,效率还算可以: 1K的数据,2.9GHz的CPU,单核下每秒能dump:36898次.大约是pyamf的5倍.但数据量 ...

  3. Python中的Numpy、SciPy、MatPlotLib安装与配置

    Python安装完Numpy,SciPy和MatplotLib后,可以成为非常犀利的科研利器.网上关于这三个库的安装都写得非常不错,但是大部分人遇到的问题并不是如何安装,而是安装好后因为配置不当,在使 ...

  4. MySQL入门很简单: 6 视图

    1. 视图含义作用 视图是虚拟的表,是从数据率中一个或多个表中导出来的表:  数据库中只存放了视图的定义,没有存放视图中的数据,数据在原先的表中:  一旦表中的数据发生变化,显示在视图中的数据也会发生 ...

  5. java线程详细版(未完待续)

    1. Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一 ...

  6. C4C销售订单中业务伙伴的自动决定功能Partner determination procedure

    例子:我新建一个Sales Order,account 字段选择ID为1001的Account:Porter LLC 创建成功后,观察这个Sales Order的Involved Party里,Bil ...

  7. VUE在页面没加载完的时候会显示原代码的处理方法

    CSS: [v-cloak] { display: none; } HTML : <div v-cloak> {{ message }} </div> 其中 v-cloak官方 ...

  8. ZOJ 2314 Reactor Cooling 带上下界的网络流

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1314 题意: 给n个点,及m根pipe,每根pipe用来流躺液体的, ...

  9. 近期流行的JavaScript框架与主题

    [新年快乐]2017年你应该关注的JavaScript框架与主题 2017-01-01 王下邀月熊 JavaScript JavaScript的繁荣促生了很多优秀的技术.框架与工具库,这空前的繁荣也给 ...

  10. 问题 B: 矩形类中运算符重载【C++】

    题目描述 定义一个矩形类,数据成员包括左下角和右上角坐标,定义的成员函数包括必要的构造函数.输入坐标的函数,实现矩形加法,以及计算并输出矩形面积的函数.要求使用提示中给出的测试函数并不得改动. 两个矩 ...