SS常见的使用场景之一就是表单登录了,而登录校验主要是经过过滤器来实现的。这里的代码使用了过滤器设计模式,将一系列的过滤器按顺序准备好,依次进行过滤。下面来看下具体的实现流程吧!html
首先看下时序图,直观感觉下:java
稍微细致点的:web
大体说明下:spring
1:最左侧是登录请求达到SS,进入过滤器链FilterChainProxysql
2:被处理登录请求的过滤器AbstractAuthenticationProcessingFilter获取,该过滤器最终的目的是生成一个表明登录用户的权限凭证(Authentication):UsernamePasswordAuthenticationToken数据库
3:过滤器调用AuthenticationManager,权限管理者,它来管理Authentication,设计模式
4:权限管理者的管理方式是经过权限提供者提供的:AbstractUserDetailsAuthenticationProvider,它是用来获取用户及权限的,并判断是否合法api
5:默认的获取用户及权限的方式是经过UserDetailsService接口定义,从命名来看,是为User服务的,因为默认的是从DB获取,所里这里调用的就是其默认的实现类JdbcDaoImpl,即从DB获取安全
6:获取完毕以后,层层返回并判断,最终符合要求就建立一个真正的Authentication,这就表明了登录用户及权限session
下面就来跟源码一块儿分享下,
看看过滤器链的核心:FilterChainProxy
它内部包含一个内部类VirtualFilterChain:
VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters); vfc.doFilter(fwRequest, fwResponse);
这里的过滤方法是调用此内部类的doFilter()方法:
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { if (currentPosition == size) { if (logger.isDebugEnabled()) { logger.debug(UrlUtils.buildRequestUrl(firewalledRequest) + " reached end of additional filter chain; proceeding with original chain"); } // Deactivate path stripping as we exit the security filter chain this.firewalledRequest.reset(); originalChain.doFilter(request, response); } else { currentPosition++; Filter nextFilter = additionalFilters.get(currentPosition - 1); if (logger.isDebugEnabled()) { logger.debug(UrlUtils.buildRequestUrl(firewalledRequest) + " at position " + currentPosition + " of " + size + " in additional filter chain; firing Filter: '" + nextFilter.getClass().getSimpleName() + "'"); } nextFilter.doFilter(request, response, this); } }
能够看到,currentPosition表明当前处理的过滤器链List additionalFilters的索引,由第一个开始,若未到达最后一个过滤器,则currentPosition++,继续处理
debug看到过滤器链以下:
[org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@5562047f, org.springframework.security.web.context.SecurityContextPersistenceFilter@53956e2d, org.springframework.security.web.header.HeaderWriterFilter@2477dc48, org.springframework.security.web.authentication.logout.LogoutFilter@170b08a9, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@aacdd0c, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@4e049f68, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@2aaa4fde, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@13079b81, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@394af762, org.springframework.security.web.session.SessionManagementFilter@3c3b6e37, org.springframework.security.web.access.ExceptionTranslationFilter@6567439d, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@5edb1d1f]
其中,这里关注的是:UsernamePasswordAuthenticationFilter
这里调用它的父类AbstractAuthenticationProcessingFilter的doFilter():
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; if (!requiresAuthentication(request, response)) { chain.doFilter(request, response); return; } if (logger.isDebugEnabled()) { logger.debug("Request is to process authentication"); } Authentication authResult; try { //调用权限验证,返回的是Authentication对象 authResult = attemptAuthentication(request, response); if (authResult == null) { // return immediately as subclass has indicated that it hasn't completed // authentication return; } sessionStrategy.onAuthentication(authResult, request, response); } catch (InternalAuthenticationServiceException failed) { logger.error( "An internal error occurred while trying to authenticate the user.", failed); unsuccessfulAuthentication(request, response, failed); return; } catch (AuthenticationException failed) { // Authentication failed unsuccessfulAuthentication(request, response, failed); return; } // Authentication success if (continueChainBeforeSuccessfulAuthentication) { chain.doFilter(request, response); } successfulAuthentication(request, response, chain, authResult); }
主要调用的是authResult = attemptAuthentication(request, response)方法,该方法定义:
public abstract Authentication attemptAuthentication
该类是须要被子类重写的,也就是UsernamePasswordAuthenticationFilter的attemptAuthentication:
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException( "Authentication method not supported: " + request.getMethod()); } String username = obtainUsername(request); String password = obtainPassword(request); if (username == null) { username = ""; } if (password == null) { password = ""; } username = username.trim(); //建立一个Authentication实例 UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken( username, password); // Allow subclasses to set the "details" property setDetails(request, authRequest); //获取AuthenticationManager,这里就是Spring启动的时候new出来的ProviderManager return this.getAuthenticationManager().authenticate(authRequest); }
这里的UsernamePasswordAuthenticationToken是一个权限的凭证:
包括了用户名,密码,ip,sessionId,是否已受权过一级权限集合。
继续调用ProviderManager的authenticate()方法,以下:
public Authentication authenticate(Authentication authentication) throws AuthenticationException { Class<? extends Authentication> toTest = authentication.getClass(); AuthenticationException lastException = null; Authentication result = null; boolean debug = logger.isDebugEnabled(); for (AuthenticationProvider provider : getProviders()) { if (!provider.supports(toTest)) { continue; } try { //调用provider的authenticate,这里能够自定义扩展 result = provider.authenticate(authentication); if (result != null) { copyDetails(authentication, result); break; } } ... } if (result == null && parent != null) { // Allow the parent to try. try { result = parent.authenticate(authentication); } catch (AuthenticationException e) { lastException = e; } } if (result != null) { //认证成功,清除密码等信息 if (eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) { ((CredentialsContainer) result).eraseCredentials(); } eventPublisher.publishAuthenticationSuccess(result); return result; } prepareException(lastException, authentication); throw lastException; }
经过判断发现,调用了result = parent.authenticate(authentication);即ProviderManager自己,它包含的provider为[org.springframework.security.authentication.dao.DaoAuthenticationProvider],这里是能够自定义扩展的
这里调用的是DaoAuthenticationProvider父类AbstractUserDetailsAuthenticationProvider的authenticate()方法:
public Authentication authenticate(Authentication authentication) throws AuthenticationException { // Determine username String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED" : authentication.getName(); boolean cacheWasUsed = true; UserDetails user = this.userCache.getUserFromCache(username); if (user == null) { cacheWasUsed = false; try { //调用DaoAuthenticationProvider的获取用户方法 user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication); } catch (UsernameNotFoundException notFound) { //看到这里的异常转换,统一转换成了BadCredentialsException //能够经过在子类中重写父类的属性去掉转换:super.setHideUserNotFoundExceptions(false) logger.debug("User '" + username + "' not found"); if (hideUserNotFoundExceptions) { throw new BadCredentialsException(messages.getMessage( "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } else { throw notFound; } } Assert.notNull(user, "retrieveUser returned null - a violation of the interface contract"); } try { //这里已经获取到DB中的用户,判断用户是否锁定,启用,过时 preAuthenticationChecks.check(user); //调用DaoAuthenticationProvider,判断用户的密码是否正确 additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication); } catch (AuthenticationException exception) { if (cacheWasUsed) { // There was a problem, so try again after checking // we're using latest data (i.e. not from the cache) cacheWasUsed = false; user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication); preAuthenticationChecks.check(user); additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication); } else { throw exception; } } postAuthenticationChecks.check(user); if (!cacheWasUsed) { this.userCache.putUserInCache(user); } Object principalToReturn = user; if (forcePrincipalAsString) { principalToReturn = user.getUsername(); } return createSuccessAuthentication(principalToReturn, authentication, user); }
这里调用了DaoAuthenticationProvider的retrieveUser()方法,返回一个UserDetail实例
UserDetails loadedUser; try { //获取UserDetailService,能够扩展为本身的获取用户的方法 //要注意这里仅仅传入了username,获取到用户以后难以进行其余操做了,返回的用户就是SS框架中使用的用户了 loadedUser = this.getUserDetailsService().loadUserByUsername(username); } catch (UsernameNotFoundException notFound) { if (authentication.getCredentials() != null) { String presentedPassword = authentication.getCredentials().toString(); passwordEncoder.isPasswordValid(userNotFoundEncodedPassword, presentedPassword, null); } throw notFound; }
这里看到这里是调用了UserDetailsService实现类,若是没有扩展,这默认使用JdbcDaoImpl,它同时也继承了JdbcDaoSupport,基本是基于Spring Data JPA实现的DB查询:
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { List<UserDetails> users = loadUsersByUsername(username); if (users.size() == 0) { logger.debug("Query returned no results for user '" + username + "'"); throw new UsernameNotFoundException(messages.getMessage( "JdbcDaoImpl.notFound", new Object[] { username }, "Username {0} not found")); } UserDetails user = users.get(0); // contains no GrantedAuthority[] Set<GrantedAuthority> dbAuthsSet = new HashSet<GrantedAuthority>(); if (enableAuthorities) { //从DB中将该用户相关联的[权限]查询出来并存储 dbAuthsSet.addAll(loadUserAuthorities(user.getUsername())); } if (enableGroups) { //从DB中将该用户相关联的[组权限]查询出来并存储 dbAuthsSet.addAll(loadGroupAuthorities(user.getUsername())); } List<GrantedAuthority> dbAuths = new ArrayList<GrantedAuthority>(dbAuthsSet); //添加自定义的权限,须要子类本身实现 addCustomAuthorities(user.getUsername(), dbAuths); if (dbAuths.size() == 0) { logger.debug("User '" + username + "' has no authorities and will be treated as 'not found'"); throw new UsernameNotFoundException(messages.getMessage( "JdbcDaoImpl.noAuthority", new Object[] { username }, "User {0} has no GrantedAuthority")); } //new出一个UserDetail实例 return createUserDetails(username, user, dbAuths); }
通常状况下能够扩展UserDetailsService,实现本身的获取用户,权限,建立用户的逻辑,该方法只是须要返回一个UserDetail实例
看下JdbcDaoImpl查询用户方法:
protected List<UserDetails> loadUsersByUsername(String username) { return getJdbcTemplate().query(usersByUsernameQuery, new String[] { username }, new RowMapper<UserDetails>() { public UserDetails mapRow(ResultSet rs, int rowNum) throws SQLException { String username = rs.getString(1); String password = rs.getString(2); boolean enabled = rs.getBoolean(3); return new User(username, password, enabled, true, true, true, AuthorityUtils.NO_AUTHORITIES); } }); }
其中查询用户的sql已在class中指定了:
public static final String DEF_USERS_BY_USERNAME_QUERY = "select username,password,enabled " + "from users " + "where username = ?";
这里默认从DB中获取到了一个用户以下:
通过最后的createUserDetails(username, user, dbAuths)返回一个全新的用户实例:
能够看到,查询出的权限已经被set到了用户属性中
返回用户以后,继续回到AbstractUserDetailsAuthenticationProvider的authenticate()方法,上面源码中已标注了继续进行用户判断,包括是否启用,锁定,过时:
preAuthenticationChecks.check(user)
能够看到用户属性全都是true,校验经过(建立UserDetail时默认的都是true)!
继续判断密码是否正确:
additionalAuthenticationChecks(user,
(UsernamePasswordAuthenticationToken) authentication)
这个方法的定义:protected abstract void additionalAuthenticationChecks
仍然是须要被子类继承重写的
因为这里没有扩展DaoAuthenticationProvider类,因此这里就调用了子类DaoAuthenticationProvider的方法:
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { Object salt = null; //盐值 if (this.saltSource != null) { salt = this.saltSource.getSalt(userDetails); } if (authentication.getCredentials() == null) { logger.debug("Authentication failed: no credentials provided"); throw new BadCredentialsException(messages.getMessage( "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } String presentedPassword = authentication.getCredentials().toString(); //判断密码是否有效 if (!passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword, salt)) { logger.debug("Authentication failed: password does not match stored value"); throw new BadCredentialsException(messages.getMessage( "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } }
这里没有重写PasswordEncoder,SS使用了默认的加解密,最终经过:
BCrypt.checkpw(rawPassword.toString(), encodedPassword)实现
校验经过
走到这里,AbstractUserDetailsAuthenticationProvider的authenticate()方法即将执行结束,用户,权限已经查询出来了,属性,密码等也校验了,可是该方法要返回一个Authentication对象,这里还未执行。
由前所述,在最开始的UsernamePasswordAuthenticationFilter中已经经过登陆的用户名,密码等信息建立一个Authentication:UsernamePasswordAuthenticationToken,可是这个权限对象是未通过权限认证的,是不可靠的,因此要对它进行更新,也就是最后一句:
return createSuccessAuthentication(principalToReturn, authentication, user);
protected Authentication createSuccessAuthentication(Object principal, Authentication authentication, UserDetails user) { // Ensure we return the original credentials the user supplied, // so subsequent attempts are successful even with encoded passwords. // Also ensure we return the original getDetails(), so that future // authentication events after cache expiry contain the details UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken( principal, authentication.getCredentials(), authoritiesMapper.mapAuthorities(user.getAuthorities())); result.setDetails(authentication.getDetails()); return result; }
这里就是经过查询出的信息从新建立了一个Authentication:UsernamePasswordAuthenticationToken对象,并返回!
至此,在ProviderManager中的权限校验方法已经执行完毕,SS框架已经拿到了真实的登录用户了
而后执行密码等凭证清除方法,保证安全,最后进行认证成功的事件发布
走到这里,过滤器链基本就执行完毕了,后续继续进行doFilter以后的方法了
--------------------
我这边也简单的扩展了常见类,用于实现一个权限API接口验证:
首先是启动配置类:
@Order(99) @Profile("auth") @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) static class SpringSecurityConfigurer extends WebSecurityConfigurerAdapter { @Autowired private JdbcUserDetailsManager userDetailsManager; @Autowired private UserRepository userRepository; @Value("${umUrl}") private String umUrl; public static final String USER_ROLE = "user"; @Override protected void configure(HttpSecurity http) throws Exception { UmAuthenticationFailureHandler failHandler = new UmAuthenticationFailureHandler(); http.csrf().disable(); http.headers().frameOptions().sameOrigin(); http.authorizeRequests() .antMatchers("/openapi/**", "/vendor/**", "/styles/**", "/scripts/**", "/views/**", "/img/**") .permitAll() .antMatchers("/**") .hasAnyRole(USER_ROLE); http.formLogin() .loginPage("/signin") .permitAll() .failureHandler(failHandler) // .failureUrl("/signin?#/error") .and() .httpBasic(); http.logout() .invalidateHttpSession(true) .clearAuthentication(true) .logoutSuccessUrl("/signin?#/logout"); http.exceptionHandling() .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/signin")); System.out.println(umUrl); //扩展登录校验 //userService UmUserDetailsService userService = new UmUserDetailsService(userDetailsManager,userRepository); //provider AuthenticationProvider umDaoAuthenticationProvider = new UmDaoAuthenticationProvider(userService,umUrl); // AuthenticationProvider umDaoAuthenticationProvider = new UmDaoAuthenticationProvider(userService,userDetailsManager); List<AuthenticationProvider> providers = new ArrayList<AuthenticationProvider>(); providers.add(umDaoAuthenticationProvider); //authManager // UmAuthenticationManager mamager = new UmAuthenticationManager(providers); // UmAuthenticationManager umAuthenticationManager = new UmAuthenticationManager(providers,mamager); UmAuthenticationManager umAuthenticationManager = new UmAuthenticationManager(providers); //filter UmUserPwdAuthenticationFilter umUserPwdAuthenticationFilter = new UmUserPwdAuthenticationFilter(umAuthenticationManager); //add filter to chain http.authenticationProvider(umDaoAuthenticationProvider).addFilterAfter(umUserPwdAuthenticationFilter,UmUserPwdAuthenticationFilter.class); } }
该类里面主要是新增的校验扩展类,最终造成一个过滤器并加入到过滤器链中
相关类以下:
public class UmUserPwdAuthenticationFilter extends UsernamePasswordAuthenticationFilter{ AuthenticationManager umAuthenticationManager = null; public UmUserPwdAuthenticationFilter (UmAuthenticationManager umAuthenticationManager) { this.umAuthenticationManager = umAuthenticationManager; setAuthenticationManager(umAuthenticationManager); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { System.out.println("--------------------MyUserPwdAuthenticationProvider-------------"); return super.attemptAuthentication(request, response); } }
public class UmAuthenticationManager extends ProviderManager{ public UmAuthenticationManager(List<AuthenticationProvider> providers) { super(providers); } public UmAuthenticationManager(List<AuthenticationProvider> providers,UmAuthenticationManager umAuthenticationManager) { super(providers,umAuthenticationManager); } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { System.out.println("------------------------UmAuthenticationManager---------------------------"); return authentication; } }
@Service public class UmUserDetailsService implements UserDetailsService { protected final Log logger = LogFactory.getLog(getClass()); private JdbcUserDetailsManager userDetailsManager; private UserRepository userRepository; public UmUserDetailsService() { } public UmUserDetailsService(JdbcUserDetailsManager userDetailsManager, UserRepository userRepository) { this.userDetailsManager = userDetailsManager; this.userRepository = userRepository; } /** * 原本能够调用框架的JdbcDaoImpl#loadUserByUsername从数据库获取用户, * 可是若是登录用户没有存储到DB,那么获取到的用户为null,后续框架鉴权不过,就走不到UM鉴权 * 因此重写了loadUserByUsername方法,考虑不在这里进行DB查询 * 但又因为这里重写的方法参数只有username,没有password,没法进行UM鉴权,只能考虑往前重写父类方法 可是protected final * UserDetails retrieveUser,是没法继承重写的 因此这里只能新建一个非空校验用户UserDetail,用以跨过框架的校验 * 后续发现跨过框架校验后,没法将DB查出的用户替换掉校验用户,因此只能在这里查询DB用户 */ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { logger.info("UmUserDetailsService#loadUserByUsername :username = " + username); // 查询当前用户是否存在于DB String usersByUsernameQuery = "select id,username,email,enabled from users where username = ?"; List<UserInfo> userList = userDetailsManager.getJdbcTemplate().query(usersByUsernameQuery, new String[] { username }, new RowMapper<UserInfo>() { public UserInfo mapRow(ResultSet rs, int rowNum) throws SQLException { int userId = rs.getInt(1); String username = rs.getString(2); String email = rs.getString(3); boolean enabled = rs.getBoolean(4); return new UserInfo(userId + "", username, email, enabled ? "1" : "0"); } }); // user exists if (userList != null && userList.size() > 0) { logger.info("UmUserDetailsService#loadUserByUsername get username from db success :username = " + username); return userList.get(0); } else { throw new InternalAuthenticationServiceException("NO_REGISTER:还没有开通配置平台帐号,请联系ZHUANGJIAJIE778开通"); } } public JdbcUserDetailsManager getUserDetailsManager() { return userDetailsManager; } public UserRepository getUserRepository() { return userRepository; } }
public class UmDaoAuthenticationProvider extends DaoAuthenticationProvider{ private PasswordEncoder encoder = new BCryptPasswordEncoder(); private JdbcUserDetailsManager userDetailsManager; private String umUrl; public UmDaoAuthenticationProvider(UmUserDetailsService umUserDetailsService,String umUrl) { super.setHideUserNotFoundExceptions(false); //禁止包装异常 this.umUrl = umUrl; this.userDetailsManager = userDetailsManager; setUserDetailsService(umUserDetailsService); } // public UmDaoAuthenticationProvider(UmUserDetailsService umUserDetailsService,JdbcUserDetailsManager userDetailsManager) { // super.setHideUserNotFoundExceptions(false); // this.umUserDetailsService = umUserDetailsService; // this.userDetailsManager = userDetailsManager; // setUserDetailsService(umUserDetailsService); // } @SuppressWarnings("deprecation") protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { Object salt = null; // if (this.saltSource != null) { // salt = this.saltSource.getSalt(userDetails); // } if (authentication.getCredentials() == null) { logger.debug("Authentication failed: no credentials provided"); throw new BadCredentialsException(messages.getMessage( "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } String username = authentication.getPrincipal().toString(); String presentedPassword = authentication.getCredentials().toString(); logger.info("MyDaoAuthenticationProvider # additionalAuthenticationChecks : pppp = " + presentedPassword); if(username.equals("apollo")) { if("apolloadmin".equals(presentedPassword)) { logger.error("login success : no need to UM authenticate user : [username = " + username + "] : "); return; } else { logger.error("login fail : pwd error : [username = " + username + "] : "); throw new InternalAuthenticationServiceException("login fail[username = " + username + " ] : username or pwd error!"); } // } else if(username.equals("yangli1")) { // logger.error("UM鉴权失败[username = " + username + "] : "); // throw new InternalAuthenticationServiceException("用户名或者密码错误---自定义"); } // logger.info("UM鉴权成功[username = " + username + "]"); //开始UM鉴权 String URL_INFO = umUrl + "/common/checkUUU.shtml"; // String URL_INFO = "http://localhost:8888/smp-cms-web/common/checkUmUser.shtml"; logger.info("UM authenticate url : [URL_INFO = " + URL_INFO + "]"); NameValuePair[] data = {new NameValuePair("uuu", authentication.getPrincipal().toString()), new NameValuePair("ppp", presentedPassword)}; try { Map<String, Object> resultMap = executeHttp(URL_INFO,data); if(resultMap.get("resultCode") != null && resultMap.get("resultCode").equals("00")) { logger.info("UM authenticate success : [username = " + username + "]"); } else { logger.error("UM authenticate fail : [username = " + username + "]"); throw new InternalAuthenticationServiceException("UM authenticate fail : [username = " + username + " ] : 用户名或者密码错误!"); } } catch (Exception e) { logger.error("UM authenticate fail : [username = " + username + "] : " + e.getMessage(),e); throw new InternalAuthenticationServiceException("UM authenticate fail : [username = " + username + " ] :" + " invoke um authenticate interface error : " + e.getMessage(),e); } // if (!passwordEncoder.isPasswordValid(userDetails.getPassword(), // presentedPassword, salt)) { // logger.debug("Authentication failed: password does not match stored value"); // // throw new BadCredentialsException(messages.getMessage( // "AbstractUserDetailsAuthenticationProvider.badCredentials", // "Bad credentials")); // } } protected Map<String, Object> executeHttp(String URL, NameValuePair[] data) throws Exception { Map<String, Object> resultMap = new HashMap<String, Object>(); logger.info("UmDaoAuthenticationProvider#executeHttp#url:[" + JSON.toJSONString(data) + "]"); logger.info("UmDaoAuthenticationProvider#executeHttp#address:[" + URL + "]"); String resBodyStr = ""; int code = 0; try { HttpClient httpClient = new HttpClient(); PostMethod postMethod = new PostMethod(URL); postMethod.setRequestBody(data); postMethod.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8"); httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(10000); httpClient.getHttpConnectionManager().getParams().setSoTimeout(10000); code = httpClient.executeMethod(postMethod);// 执行postMethod,返回状态码 resBodyStr = postMethod.getResponseBodyAsString(); logger.info("UmDaoAuthenticationProvider#executeHttp#responseCode:[" + code + "]#responseMsg:[:" + resBodyStr + "]"); // 状态码为200时,成功请求,其中返回CODE非00,均表示不正常 if (code == 200 && resBodyStr != null) { Map<String, Object> map = JSON.parseObject(resBodyStr, Map.class); resultMap.put("resultCode", map.get("CODE")); resultMap.put("resultMsg", map.get("MSG")); if (map.get("CODE").equals("00")) { resultMap.put("resultData", map.get("DATA")); } } else { resultMap.put("resultCode", "01"); resultMap.put("resultMsg", "invoke um authenticate interface error , contact ITer plz"); } } catch (Exception e) { e.printStackTrace(); logger.error("UmDaoAuthenticationProvider#executeHttp#exception#code[" + code + "]#resBodyStr[:" + resBodyStr + "]" + e.getMessage(),e); resultMap.put("resultCode", "01"); resultMap.put("resultMsg", "invoke um authenticate interface error , contact ITer plz"); } return resultMap; } }
public class UmAuthenticationFailureHandler implements AuthenticationFailureHandler{ protected final Log logger = LogFactory.getLog(getClass()); private String defaultFailureUrl = "/signin?#/error"; private static String NO_REGISTER = "NO_REGISTER"; private boolean forwardToDestination = false; private boolean allowSessionCreation = true; private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); /** * Performs the redirect or forward to the {@code defaultFailureUrl} if set, otherwise * returns a 401 error code. * <p> * If redirecting or forwarding, {@code saveException} will be called to cache the * exception for use in the target view. */ public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { if (defaultFailureUrl == null) { logger.debug("No failure URL set, sending 401 Unauthorized error"); response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed: " + exception.getMessage()); } else { saveException(request, exception); //初始化 defaultFailureUrl = "/signin?#/error"; //未开通帐号的错误 if(exception.getMessage().startsWith(NO_REGISTER)) { defaultFailureUrl = defaultFailureUrl + "="+ NO_REGISTER; } if (forwardToDestination) { logger.debug("Forwarding to " + defaultFailureUrl); request.getRequestDispatcher(defaultFailureUrl).forward(request, response); } else { logger.debug("Redirecting to " + defaultFailureUrl); redirectStrategy.sendRedirect(request, response, defaultFailureUrl); } } } /** * Caches the {@code AuthenticationException} for use in view rendering. * <p> * If {@code forwardToDestination} is set to true, request scope will be used, * otherwise it will attempt to store the exception in the session. If there is no * session and {@code allowSessionCreation} is {@code true} a session will be created. * Otherwise the exception will not be stored. */ protected final void saveException(HttpServletRequest request, AuthenticationException exception) { if (forwardToDestination) { request.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception); } else { HttpSession session = request.getSession(false); if (session != null || allowSessionCreation) { request.getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception); } } } }
实现了功能,可是还没优化,能够参考下