您的位置:首页 > 编程语言 > Java开发

spring security 一个验证码登录例子

2016-07-11 17:03 453 查看
看完shiro,在看spring security感觉快了很多,最开始看spring security的时候,非常晕,看完我觉得spring security做了太多事,以至于程序员都不知道,是怎么实现的,这样的

后果就是 当出现错误,或者需要修改的时候感觉无从下手。

个人理解,若有错误,请指正。

spring security跟shiro类似,都是使用过滤器来认证和授权,不同的是spring seciruty是实现了一个过滤器链,每个请求都要经过,我们可以使用自动配置,这样spring security自动帮我们配置了这一系列过滤器,也可以自定义过滤器放在它的过滤器链中。

验证码或密码登录,需要重新修改认证过滤器

package com.test.hello.security;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.AbstractAuthenticationToken;
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.web.authentication.UsernamePasswordAuthenticationFilter;

public class KdUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter{
private boolean postOnly = true;
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (this.postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}

String username = obtainUsername(request);
String password = obtainPassword(request);
String type = request.getParameter("j_type");

if (username == null) {
username = "";
}

if (password == null) {
password = "";
}

if (type == null) {
type = "1";
}

username = username.trim();

Authentication authRequest;
if(type.equals("1")){
authRequest = new UsernamePasswordAuthenticationToken(username, password);
}else{
authRequest = new KdUsernamePasswordAuthenticationToken(username, password,type);
}

// Allow subclasses to set the "details" property
setDetails(request, (AbstractAuthenticationToken)authRequest);

return this.getAuthenticationManager().authenticate(authRequest);
}

/**
* Provided so that subclasses may configure what is put into the authentication request's details
* property.
*
* @param request that an authentication request is being created for
* @param authRequest the authentication request object that should have its details set
*/
protected void setDetails(HttpServletRequest request, AbstractAuthenticationToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}

}


type为2时候,使用验证码登录,token- >provider ->
token

package com.test.hello.security;

import java.util.Collection;

import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;

public class KdUsernamePasswordAuthenticationToken extends AbstractAuthenticationToken{

//~ Instance fields ================================================================================================

/**
*
*/
private static final long serialVersionUID = 1L;
private final Object principal;
private Object credentials;
private String type;

//~ Constructors ===================================================================================================

/**
* This constructor can be safely used by any code that wishes to create a
* <code>UsernamePasswordAuthenticationToken</code>, as the {@link
* #isAuthenticated()} will return <code>false</code>.
*
*/
public KdUsernamePasswordAuthenticationToken(Object principal, Object credentials,String type) {
super(null);
this.principal = principal;
this.credentials = credentials;
this.type = type;
setAuthenticated(false);
}

/**
* This constructor should only be used by <code>AuthenticationManager</code> or <code>AuthenticationProvider</code>
* implementations that are satisfied with producing a trusted (i.e. {@link #isAuthenticated()} = <code>true</code>)
* authentication token.
*
* @param principal
* @param credentials
* @param authorities
*/
public KdUsernamePasswordAuthenticationToken(Object principal, Object credentials,String type, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
this.type = type;
super.setAuthenticated(true); // must use super, as we override
}

//~ Methods ========================================================================================================

public Object getCredentials() {
return this.credentials;
}

public Object getPrincipal() {
return this.principal;
}

public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
if (isAuthenticated) {
throw new IllegalArgumentException(
"Once created you cannot set this token to authenticated. Create a new instance using the constructor which takes a GrantedAuthority list will mark this as authenticated.");
}

super.setAuthenticated(false);
}

@Override
public void eraseCredentials() {
super.eraseCredentials();
credentials = null;
}

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}

}


provider 重写了  密码校验方法,并且默认使用了KdJdbcDaoImpl去查询用户信息
KdAbstractUserDetailsAuthenticationProvider跟AbstractUserDetailsAuthenticationProvider一样仅仅改了authenticate方法里面的

 Assert.isInstanceOf(KdUsernamePasswordAuthenticationToken.class,

package com.test.hello.security;

import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

public class KdDaoAuthenticationProvider extends KdAbstractUserDetailsAuthenticationProvider{

private UserDetailsService userDetailsService = new KdJdbcDaoImpl();

public UserDetailsService getUserDetailsService() {
return userDetailsService;
}

public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}

@Override
public boolean supports(Class<?> authentication) {
return (KdUsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}

@SuppressWarnings("deprecation")
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails,
KdUsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
if (authentication.getCredentials() == null) {
logger.debug("Authentication failed: no credentials provided");

throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"), userDetails);
}

String presentedPassword
4000
= authentication.getCredentials().toString();

if (!userDetails.getPassword().equals(presentedPassword)) {
logger.debug("Authentication failed: password does not match stored value");

throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"), userDetails);
}else{
KdJdbcDaoImpl.userpass.remove(userDetails.getUsername());
}

}

@Override
protected UserDetails retrieveUser(String username,
KdUsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
UserDetails loadedUser;

try {
loadedUser = this.getUserDetailsService().loadUserByUsername(username);
} catch (UsernameNotFoundException notFound) {
throw notFound;
} catch (Exception repositoryProblem) {
throw new InternalAuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
}

if (loadedUser == null) {
throw new InternalAuthenticationServiceException(
"UserDetailsService returned null, which is an interface contract violation");
}
return loadedUser;
}

}


KdJdbcDaoImpl
package com.test.hello.security;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl;

public class KdJdbcDaoImpl extends JdbcDaoImpl{

public static ConcurrentHashMap<String,String> userpass = new ConcurrentHashMap<String, String>();

@Override
protected List<UserDetails> loadUsersByUsername(String username) {
List<UserDetails> list = new ArrayList<UserDetails>();
String password = userpass.get(username);
if(password != null){
list.add(new User(username, password, true, true, true, true, AuthorityUtils.NO_AUTHORITIES));
}

return list;
}

}


最后的配置
<security:http pattern="/resource/**" security="none"></security:http>
<security:http pattern="/index.jsp" security="none"></security:http>
<security:http pattern="/" security="none"></security:http>
<security:http pattern="/checkcode" security="none"></security:http>
<security:http entry-point-ref="loginUrlAuthenticationEntryPoint" >
<security:intercept-url pattern="/role/user**" access="ROLE_USER"/>
<security:intercept-url pattern="/role/admin**" access="ROLE_ADMIN"/>
<security:intercept-url pattern="/role/manager**" access="ROLE_MANAGER"/>
<security:custom-filter ref="kdUsernamePasswordAuthenticationFilter" position="FORM_LOGIN_FILTER"/>
<security:custom-filter ref="logoutFilter" position="LOGOUT_FILTER"/>
<security:access-denied-handler ref="accessDeniedHandlerImpl"/>
</security:http>

<bean id="accessDeniedHandlerImpl" class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
<property name="errorPage" value="/errorPage.jsp"></property>
</bean>
<bean id="loginUrlAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/index.jsp"></property>
</bean>

<bean id="kdUsernamePasswordAuthenticationFilter" class="com.test.hello.security.KdUsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="org.springframework.security.authenticationManager"></property>
<property name="authenticationSuccessHandler" ref="savedRequestAwareAuthenticationSuccessHandler"></property>
<property name="authenticationFailureHandler" ref="simpleUrlAuthenticationFailureHandler"></property>
</bean>

<bean id="savedRequestAwareAuthenticationSuccessHandler" class="com.test.hello.security.KdSavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/loginSuccess"></property>
</bean>
<bean id="simpleUrlAuthenticationFailureHandler" class="com.test.hello.security.KdSimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/index.jsp"></property>
</bean>

<bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<property name="filterProcessesUrl" value="/logout"></property>
<constructor-arg index="0" >
<bean class="org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler">
<property name="defaultTargetUrl" value="/index.jsp"></property>
</bean>
</constructor-arg>
<constructor-arg index="1">
<array>
<bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"></bean>
</array>
</constructor-arg>
</bean>

<bean id="org.springframework.security.authenticationManager" name="authenticationManager" class="org.springframework.security.authentication.ProviderManager" >
<property name="authenticationEventPublisher" ref="defaultAuthenticationEventPublisher"></property>
<property name="providers">
<list>
<ref bean="daoAuthenticationProvider"/>
<ref bean="anonymousAuthenticationProvider"/>
<ref bean="kdDaoAuthenticationProvider"/>
</list>
</property>
</bean>

<bean id="defaultAuthenticationEventPublisher" class="org.springframework.security.authentication.DefaultAuthenticationEventPublisher"></bean>

<bean id="anonymousAuthenticationProvider" class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
<property name="key" value="work"></property>
</bean>

<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userService"></property>
<!-- <property name="passwordEncoder" ref="bcrypt"></property> -->
</bean>
<bean id="userService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>

<bean id="kdDaoAuthenticationProvider" class="com.test.hello.security.KdDaoAuthenticationProvider">
<property name="userDetailsService" ref="kdJdbcDaoImpl"></property>
</bean>

<bean id="kdJdbcDaoImpl" class="com.test.hello.security.KdJdbcDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<base href="<%=basePath%>">

<title>My JSP 'index.jsp' starting page</title>

<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<script type="text/javascript" src="resource/js/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
$("#jtypese").change(function(){
var v = $("#jtypese").val();
if(v=='2'){
var uname = $("#usernameinput").val();
var url = "<%=basePath%>checkcode?username="+uname;
$.get(url,function(data,status){
alert("验证码: " + data + "\n发送状态: " + status);
});
}
});
});
</script>

</head>

<body>
This is my login page. <br>
<form action="j_spring_security_check" method="post">
<table>
<tr><td>用户名:</td><td><input name="j_username" value="u1" id="usernameinput"></td></tr>
<tr><td>密码/验证码:</td><td><input name="j_password" value="p1"></td></tr>
<tr><td>登录方式: </td><td><select name="j_type" id="jtypese"><option value="1">密码</option><option value="2">验证码</option></select></td></tr>
<tr><td colspan="2"> <input type="submit" value="submit"></td></tr>
</table>
</form>

异常: ${SPRING_SECURITY_LAST_EXCEPTION }<br>
失败次数:  ${SPRING_SESSION_FAIL_TIMES }
</body>
</html>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: