spring security 一个验证码登录例子
看完shiro,在看spring security感觉快了很多,最开始看spring security的时候,非常晕,看完我觉得spring security做了太多事,以至于程序员都不知道,是怎么实现的,这样的
后果就是 当出现错误,或者需要修改的时候感觉无从下手。
个人理解,若有错误,请指正。
spring security跟shiro类似,都是使用过滤器来认证和授权,不同的是spring seciruty是实现了一个过滤器链,每个请求都要经过,我们可以使用自动配置,这样spring security自动帮我们配置了这一系列过滤器,也可以自定义过滤器放在它的过滤器链中。
验证码或密码登录,需要重新修改认证过滤器
[java] view plain copy
- 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
[java] view plain copy
- 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
- *
UsernamePasswordAuthenticationToken
, as the {@link - * #isAuthenticated()} will return
false
. - *
- */
- 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
AuthenticationManager
orAuthenticationProvider
- * implementations that are satisfied with producing a trusted (i.e. {@link #isAuthenticated()} =
true
) - * 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,
[java] view plain copy
- 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 = 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
[java] view plain copy
- 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
userpass = new ConcurrentHashMap (); - @Override
- protected List
loadUsersByUsername(String username) { - List
list = new ArrayList (); - String password = userpass.get(username);
- if(password != null){
- list.add(new User(username, password, true, true, true, true, AuthorityUtils.NO_AUTHORITIES));
- }
- return list;
- }
- }
最后的配置
[java] view plain copy
[java] view plain copy
- <%@ 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">
My JSP ‘index.jsp’ starting page - This is my login page.
- 异常: ${SPRING_SECURITY_LAST_EXCEPTION }
- 失败次数: ${SPRING_SESSION_FAIL_TIMES }
用户名: | |
密码/验证码: | |
登录方式: | |
还没有评论,来说两句吧...