版本一
ajax提交思想:用filter来实现,请求的匹配
json返回数据
public class LoginAuthenticationSuccesssHandler implements AuthenticationSuccessHandler {
static final Logger logger = LogManager.getLogger(LoginAuthenticationSuccesssHandler.class.getName());
private String defaultUrl;
public void setDefaultUrl(String defaultUrl) {
this.defaultUrl = defaultUrl;
}
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
response.setContentType("application/json; charset=UTF-8");
ReturnEntity<String> returnEntity = new ReturnEntity<>();
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.writeValue(response.getWriter(), returnEntity);
}
}
以后抽空完善具体代码,现在就说下核心思路
版本二
先直接上代码:
spring-security.xml的配置文件
<?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-4.2.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd">
<http pattern="/login/**" security="none"></http>
<http auto-config="false" use-expressions="true" entry-point-ref="http403EntryPoint">
<csrf disabled="true" />
<!-- 退出 -->
<logout invalidate-session="true" logout-url="/logout.do" logout-success-url="/index.html" delete-cookies="true" />
<!-- session管理 -->
<session-management invalid-session-url="/login/timedout.do" session-fixation-protection="none"
session-authentication-error-url="/login/timedout.do">
<concurrency-control error-if-maximum-exceeded="true" expired-url="/login/timedout.do"
max-sessions="1" />
</session-management>
<!-- 拦截器 -->
<custom-filter ref="CustomUsernamePasswordAuthenticationFilter" position="FORM_LOGIN_FILTER " />
<access-denied-handler error-page="/accessDenied.htm" />
</http>
<!-- 权限管理器 -->
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="userServiceDetail">
<password-encoder ref="standardPasswordEncoder" />
</authentication-provider>
</authentication-manager>
<beans:bean id="CustomUsernamePasswordAuthenticationFilter" class="u.frame.web.trade.security.ne.MyUsernamePasswordAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="authenticationSuccessHandler" ref="customSuccessHandler" />
<beans:property name="authenticationFailureHandler" ref="failureHandler" />
<beans:property name="filterProcessesUrl" value="/j_spring_security_check.do" />
<!-- <beans:property name="usernameParameter" value="jsonUsername" /> -->
<!-- <beans:property name="passwordParameter" value="j_password" /> -->
</beans:bean>
<!-- 登录成功的处理 -->
<beans:bean id="customSuccessHandler" class="u.frame.web.trade.security.ne.MySimpleUrlAuthenticationSuccessHandler">
<beans:property name="defaultTargetUrl" value="/login.htm" />
<beans:property name="targetUrlParameter" value="/LoginSuccessful.htm" />
</beans:bean>
<!-- 登录失败的处理 -->
<beans:bean id="failureHandler" class="u.frame.web.trade.security.ne.MySimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl" value="/login.htm" />
</beans:bean>
<!-- 403的处理 -->
<beans:bean id="http403EntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint" />
<!-- 获得用户信息 -->
<beans:bean id="userServiceDetail" class="u.frame.web.trade.security.old.MyUserDetailServiceImpl" />
<!-- 密码加密工具 -->
<beans:bean id="standardPasswordEncoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder">
<beans:constructor-arg value="q1w2e3r4t5y6u7i8o9" />
</beans:bean>
</beans:beans>
MyUsernamePasswordAuthenticationFilter.java
package u.frame.web.trade.security.ne;
import java.io.BufferedReader;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.fasterxml.jackson.databind.ObjectMapper;
import u.frame.web.trade.model.Login;
public class MyUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private String jsonUsername;
private String jsonPassword;
@Override
protected String obtainPassword(HttpServletRequest request) {
String password = null;
if (checkJson(request)) {
password = this.jsonPassword;
} else {
password = super.obtainPassword(request);
}
return password;
}
@Override
protected String obtainUsername(HttpServletRequest request) {
String username = null;
if (checkJson(request)) {
username = this.jsonUsername;
} else {
username = super.obtainUsername(request);
}
return username;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
if (checkJson(request)) {
try {
/*
* HttpServletRequest can be read only once
*/
StringBuffer sb = new StringBuffer();
String line = null;
BufferedReader reader = request.getReader();
while ((line = reader.readLine()) != null) {
sb.append(line);
}
// json transformation
ObjectMapper mapper = new ObjectMapper();
Login login = mapper.readValue(sb.toString(), Login.class);
this.jsonUsername = login.getUserName();
this.jsonPassword = login.getPassWord();
return new UsernamePasswordAuthenticationToken(jsonUsername, jsonPassword);
} catch (Exception e) {
e.printStackTrace();
}
}
return super.attemptAuthentication(request, response);
}
public boolean checkJson(HttpServletRequest request) {
if ("application/json".equals(request.getHeader("Content-Type"))) {
return true;
}
return false;
}
}
MySimpleUrlAuthenticationSuccessHandler.java
package u.frame.web.trade.security.ne;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
public class MySimpleUrlAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication auth)
throws IOException, ServletException {
if ("application/json".equals(request.getHeader("Content-Type"))) {
/*
* USED if you want to AVOID redirect to LoginSuccessful.htm in JSON authentication
*/
response.getWriter().print("{\"responseCode\":\"SUCCESS\"}");
response.getWriter().flush();
} else {
super.onAuthenticationSuccess(request, response, auth);
}
}
}
MySimpleUrlAuthenticationFailureHandler.java
package u.frame.web.trade.security.ne;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
public class MySimpleUrlAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception)
throws IOException, ServletException {
if ("application/json".equals(request.getHeader("Content-Type"))) {
/*
* USED if you want to AVOID redirect to LoginSuccessful.htm in JSON authentication
*/
response.getWriter().print("{\"responseCode\":\"Failure\"}");
response.getWriter().flush();
} else {
// TODO Auto-generated method stub
super.onAuthenticationFailure(request, response, exception);
}
}
}
MyUserDetailServiceImpl.java
package u.frame.web.trade.security.old;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.StandardPasswordEncoder;
import u.frame.web.trade.model.Login;
public class MyUserDetailServiceImpl implements UserDetailsService {
static final Logger logger = LogManager.getLogger(MyUserDetailServiceImpl.class.getName());
@Autowired
private StandardPasswordEncoder standardPasswordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (StringUtils.isEmpty(username)) {
throw new UsernameNotFoundException("用户名不可为空!");
}
//测试用的
if (!"123".equals(username)) {
throw new UsernameNotFoundException("error");
}
Login login = new Login();
login.setUserName(username);
login.setPassWord(standardPasswordEncoder.encode("123"));
logger.info(username);
boolean enabled = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
return new org.springframework.security.core.userdetails.User(//
login.getUserName(), //
// user.getUserPassword()+"{"+user.getUserName()+"}",
login.getPassWord(), //
enabled, //
accountNonExpired, //
credentialsNonExpired, //
accountNonLocked, //
authorities//
);
}
}
思路来源于http://stackoverflow.com/questions/19500332/spring-security-and-json-authentication
整体思想,就是filter过滤拦截。
版本三
不多说,直接上代码
applicationContext-security.xml
<?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-4.2.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd">
<!-- 不需要拦截 -->
<http pattern="/login/**" security="none"></http>
<http auto-config="false" use-expressions="true" entry-point-ref="http403EntryPoint">
<csrf disabled="true" />
<headers>
<frame-options policy="SAMEORIGIN" />
<cache-control disabled="true" />
<content-type-options disabled="true" />
</headers>
<logout invalidate-session="true" logout-url="/login/logout.do" logout-success-url="/login/success.do" delete-cookies="true" />
<session-management invalid-session-url="/login/timedout.do" session-fixation-protection="none"
session-authentication-error-url="/login/timedout.do">
<concurrency-control error-if-maximum-exceeded="false" expired-url="/login/timedout.do" max-sessions="1" />
</session-management>
<!-- filter_security_interceptor -->
<custom-filter ref="mySecurityFilter" before="FILTER_SECURITY_INTERCEPTOR" />
<!-- form_login_filter -->
<custom-filter ref="CustomUsernamePasswordAuthenticationFilter" before="FORM_LOGIN_FILTER" />
</http>
<beans:bean id="CustomUsernamePasswordAuthenticationFilter" class="u.frame.web.trade.security.ne.MyUsernamePasswordAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="authenticationSuccessHandler" ref="successHandler" />
<beans:property name="authenticationFailureHandler" ref="failureHandler" />
<beans:property name="filterProcessesUrl" value="/logincheck1.do" />
<!-- <beans:property name="usernameParameter" value="jsonUsername" /> -->
<!-- <beans:property name="passwordParameter" value="j_password" /> -->
</beans:bean>
<!-- 自定义过滤器 -->
<beans:bean id="mySecurityFilter" class="u.frame.web.trade.security.old.MyFilterSecurityInterceptor" />
<!-- =========== -->
<!-- =========== -->
<!-- =========== -->
<!-- =========== -->
<!-- =========== -->
<!-- =========== -->
<!-- =========== -->
<!-- =========== -->
<!-- 认证管理器 -->
<!--验证配置,认证管理器,实现用户认证的入口,主要实现UserDetailsService接口即可 -->
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="userServiceDetail">
<password-encoder ref="standardPasswordEncoder" />
</authentication-provider>
</authentication-manager>
<!-- 登录成功的处理 -->
<beans:bean id="successHandler" class="u.frame.web.trade.security.ne.MySimpleUrlAuthenticationSuccessHandler">
<beans:property name="defaultTargetUrl" value="/login/success.do" />
<!-- <beans:property name="targetUrlParameter" value="/LoginSuccessful.htm" /> -->
</beans:bean>
<!-- 登录失败的处理 -->
<beans:bean id="failureHandler" class="u.frame.web.trade.security.ne.MySimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl" value="/login/error.do" />
</beans:bean>
<!-- 403的处理 -->
<beans:bean id="http403EntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint" />
<!-- 获得用户信息 -->
<beans:bean id="userServiceDetail" class="u.frame.web.trade.security.old.MyUserDetailServiceImpl" />
<!-- 密码加密工具 -->
<beans:bean id="standardPasswordEncoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder">
<beans:constructor-arg value="q1w2e3r4t5y6u7i8o9p0" />
</beans:bean>
</beans:beans>
MyUsernamePasswordAuthenticationFilter.java
package u.frame.web.trade.security.ne;
import java.io.BufferedReader;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.fasterxml.jackson.databind.ObjectMapper;
import u.frame.web.trade.model.Login;
public class MyUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
static Log log = LogFactory.getLog(MySimpleUrlAuthenticationFailureHandler.class);
// 用户的登录信息
private Login login;
@Override
protected String obtainPassword(HttpServletRequest request) {
System.out.println("MyUsernamePasswordAuthenticationFilter-obtainPassword");
if (checkJson(request)) {
if (login != null) {
return login.getPassWord();
}
}
// }
return super.obtainPassword(request);
}
@Override
protected String obtainUsername(HttpServletRequest request) {
System.out.println("MyUsernamePasswordAuthenticationFilter-obtainUsername");
if (checkJson(request)) {
if (login != null) {
return login.getUserName();
}
}
return super.obtainUsername(request);
}
public boolean checkJson(HttpServletRequest request) {
try {
if ("application/json".equals(request.getHeader("Content-Type"))) {
StringBuffer sb = new StringBuffer();
String line = null;
BufferedReader reader;
reader = request.getReader();
while ((line = reader.readLine()) != null) {
sb.append(line);
}
if (StringUtils.isNotEmpty(sb.toString())) {
ObjectMapper mapper = new ObjectMapper();
login = mapper.readValue(sb.toString(), Login.class);
}
return true;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}
}
思想来源:
http://docs.spring.io/spring-security/site/docs/3.0.x/reference/ns-config.html
说明:
简单的说,就是重写http/form-login,使用http/form-login的另一种形式UsernamePasswordAuthenticationFilter就可以了。
版本4
为了解决UsernameNotFoundException的异常抛出问题
直接上代码:
applicationContext-security.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:security="http://www.springframework.org/schema/security" 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-4.2.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd">
<!-- 不需要拦截 -->
<security:http pattern="/login/**" security="none"></security:http>
<security:http auto-config="false" use-expressions="true" entry-point-ref="http403EntryPoint">
<security:csrf disabled="true" />
<security:headers>
<security:frame-options policy="SAMEORIGIN" />
<security:cache-control disabled="true" />
<security:content-type-options disabled="true" />
</security:headers>
<!-- 退出 -->
<security:logout invalidate-session="true" logout-url="/login/logout.do" logout-success-url="/login/outSuccess.do"
delete-cookies="true" />
<!-- session超时 -->
<security:session-management invalid-session-url="/login/timedout.do" session-fixation-protection="none"
session-authentication-error-url="/login/timedout.do">
<security:concurrency-control error-if-maximum-exceeded="false" expired-url="/login/timedout.do"
max-sessions="1" />
</security:session-management>
<!-- filter_security_interceptor -->
<security:custom-filter ref="mySecurityFilter" before="FILTER_SECURITY_INTERCEPTOR" />
<!-- form_login_filter -->
<security:custom-filter ref="CustomUsernamePasswordAuthenticationFilter" before="FORM_LOGIN_FILTER" />
</security:http>
<bean id="CustomUsernamePasswordAuthenticationFilter" class="u.frame.web.trade.security.MyUsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="authenticationSuccessHandler" ref="successHandler" />
<property name="authenticationFailureHandler" ref="failureHandler" />
<property name="filterProcessesUrl" value="/logincheck.do" />
</bean>
<!-- 自定义过滤器 -->
<bean id="mySecurityFilter" class="u.frame.web.trade.security.MyFilterSecurityInterceptor" />
<!-- 认证管理器 -->
<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<constructor-arg>
<list>
<ref bean="daoAuthenticationProvider" />
</list>
</constructor-arg>
</bean>
<!-- 认证提供类 -->
<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userServiceDetail" />
<property name="passwordEncoder" ref="standardPasswordEncoder" />
<!--不隐藏错误-->
<property name="hideUserNotFoundExceptions" value="false" />
</bean>
<!-- 登录成功的处理 -->
<bean id="successHandler" class="u.frame.web.trade.security.MySimpleUrlAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/login/success.do" />
<!-- <property name="targetUrlParameter" value="/LoginSuccessful.htm" /> -->
</bean>
<!-- 登录失败的处理 -->
<bean id="failureHandler" class="u.frame.web.trade.security.MySimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/login/error.do" />
</bean>
<!-- 403的处理 -->
<bean id="http403EntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint" />
<!-- 获得用户信息 -->
<bean id="userServiceDetail" class="u.frame.web.trade.security.MyUserDetailServiceImpl" />
<!-- 密码加密工具 -->
<bean id="standardPasswordEncoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder">
<constructor-arg value="q1w2e3r4t5y6u7i8o9" />
</bean>
</beans>