步驟:前端
1.繼承 WebSecurityConfigurerAdapter.class,其中使用兩個過濾器,一個spring scurity自帶的UsernamePasswordAuthenticationFilter,一個是自定義的過濾器ZTSSOAuthenticationProcessingFilter ,他們都繼承AbstractAuthenticationProcessingFilter,該filter的功能是去指定攔截界面發送的post請求,而後加入到filter chain 中去。java
import com.idoipo.ibt.service.LoginAuthenticationSuccessHandler; import com.idoipo.ibt.service.SmsAuthenticationProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; /** * Created by pingli on 2018-10-13. */ @Configuration @EnableWebSecurity @SuppressWarnings("unused") public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter{ @Value("${com.cookie}") private String sessionCookieName; @Value("${com..cookie.token}") private String tokenCookie; @Value("${com.cookie.timer}") private String timerCookie; @Value("${com.cookie.curp}") private String curpCookie; @Value("${com.cookie.gw}") private String gwCookie; @Value("${com.cookie.commondomain}") private String cdCookie; @Value("${com.index}") private String homeUrl; @Value("${com.main}") private String mainUrl; @Value("${zt.ssoUrl}") private String ssoUrl; @Value("${zt.appId}") private String appId; @Value("${com.idoipo.infras.ibt}") private String ibtUrl; @Autowired private SmsAuthenticationProvider authenticationProvider; @Autowired private ZTSSOAuthenticationProvider ztssoAuthenticationProvider; @Autowired @Qualifier("authenticationManagerBean") private AuthenticationManager authenticationManager; @Autowired private LoginAuthenticationSuccessHandler successHandler; @Override protected void configure(HttpSecurity http) throws Exception { String logoutUrl="/logout"; String loginUrl="/login"; String loginMiddleUrl="/SsoLogin"; String ssoUrlRequest = ssoUrl+"?a="+appId+"&"+"r="+ibtUrl+loginMiddleUrl; http.formLogin()//處理登陸 .loginPage(ssoUrlRequest) .successHandler(successHandler) .loginProcessingUrl(loginUrl) .usernameParameter("mobile") .passwordParameter("check") .failureUrl(ssoUrlRequest) .permitAll() .and() .authorizeRequests()//請求受權 .antMatchers("/",homeUrl,"/file/supload","/dist/**",loginMiddleUrl).permitAll()//首頁與前端資源能夠直接訪問 .antMatchers(logoutUrl,"/heartbeat").authenticated() .antMatchers(loginUrl).anonymous() .anyRequest().authenticated() .and() .logout() .logoutUrl(logoutUrl) .logoutSuccessUrl(homeUrl) .invalidateHttpSession(true) .deleteCookies(sessionCookieName,tokenCookie,timerCookie,curpCookie,gwCookie,cdCookie) .logoutRequestMatcher(new AntPathRequestMatcher(logoutUrl, "GET")) .and() .csrf() .disable() .addFilterAt(ztssoAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class);//增長過濾/SsoLogin接口請求 } @Bean public ZTSSOAuthenticationProcessingFilter ztssoAuthenticationFilter() { ZTSSOAuthenticationProcessingFilter filter = new ZTSSOAuthenticationProcessingFilter(); filter.setAuthenticationManager(authenticationManager); filter.setAuthenticationSuccessHandler(successHandler); return filter; } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(this.authenticationProvider) .authenticationProvider(this.ztssoAuthenticationProvider); } }
import com.idoipo.ibt.controllers.HomeController; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * Created by pingli on 2018-10-06 * 攔截請求 */ public class ZTSSOAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter { private Logger logger = LoggerFactory.getLogger(ZTSSOAuthenticationProcessingFilter.class); public static final String SPRING_SECURITY_FORM_ZT_TOKEN = "Token"; private String ZTToken = SPRING_SECURITY_FORM_ZT_TOKEN; private boolean postOnly = true; public ZTSSOAuthenticationProcessingFilter() { super(new AntPathRequestMatcher("/SsoLogin", "POST")); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { logger.info("進入sso過濾器"); if (postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException( "Authentication method not supported: " + request.getMethod()); } String token = obtainToken(request); if (token == null) { token = ""; } AbstractAuthenticationToken authRequest = new ZTSSOAuthenticationToken(null,token); // Allow subclasses to set the "details" property setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } protected String obtainToken(HttpServletRequest request) { return request.getParameter(ZTToken); } protected void setDetails(HttpServletRequest request, AbstractAuthenticationToken authRequest) { authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); } }
2web
ZTSSOAuthenticationProcessingFilter 攔截到SsoLogin 的post請求後,須要一個繼承
AbstractAuthenticationToken的token類來存獲得的第三方的token參數。
import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.SpringSecurityCoreVersion; import java.util.Collection; /** * Created by pingli on 2018-10-06 * 生成登陸session,同用戶不用再校驗 */ public class ZTSSOAuthenticationToken extends AbstractAuthenticationToken { private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; private final Object principal; private String credentials; public ZTSSOAuthenticationToken(Object principal,String credentials) { super(null); this.principal = principal; this.credentials = credentials; super.setAuthenticated(true); } public ZTSSOAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) { super(authorities); this.principal = principal; this.credentials = null; super.setAuthenticated(true); // must use super, as we override } // ~ Methods // ======================================================================================================== public String getCredentials() { return this.credentials; } public Object getPrincipal() { return this.principal; } public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { if (isAuthenticated) { throw new IllegalArgumentException( "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); } super.setAuthenticated(false); } @Override public void eraseCredentials() { super.eraseCredentials(); credentials = null; } }
3.獲得參數後,須要根據token,去第三方查詢用戶信息,用戶生成本身系統的token,這一步在實現了spring
AuthenticationProvider的類中去處理,這個類須要去指定
ZTSSOAuthenticationToken 支持他,因此須要重寫
supports方法,從而關聯上ZTSSOAuthenticationProcessingFilter ,
ZTSSOAuthenticationToken ,
AuthenticationProvider這三個類,filter獲得請求,token去保存參數,provider去獲取支持的token類的參數,從而完成一條線,後續其餘驗證也能夠採用該種方式去增長,注意若是要增長成功後的處理,請注意
繼承了WebSecurityConfigurerAdapter中添加
filter.setAuthenticationSuccessHandler(successHandler);去設置受權成功後能夠進行一些後續處理,好比生成token字符串到前臺,或者指定默認的跳轉路徑
import com.idoipo.ibt.bto.AccountInfo; import com.idoipo.ibt.bto.UserDetail; import com.idoipo.ibt.service.UserService; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.stereotype.Component; /** * Created by pingli on 2018-10-06 * sso驗證類 */ @Component public class ZTSSOAuthenticationProvider implements AuthenticationProvider { private Logger logger= LoggerFactory.getLogger(ZTSSOAuthenticationProvider.class); @Autowired private UserService userService; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String ZTToken = (authentication.getCredentials()==null)?null:authentication.getCredentials().toString(); if (StringUtils.isEmpty(ZTToken)) { throw new BadCredentialsException("token不能爲空"); } AccountInfo accountInfo = userService.getUserInfoBySSO(ZTToken); logger.info("當前sso反回帳號信息={}",accountInfo); UserDetail userDetail = userService.getTokenByPsnId(accountInfo.getAccount()); ZTSSOAuthenticationToken result = new ZTSSOAuthenticationToken(userDetail,userDetail.getJwtToken()); result.setDetails(authentication.getDetails()); return result; } @Override public boolean supports(Class<?> authentication) { logger.info(this.getClass().getName() + "---supports"); return (ZTSSOAuthenticationToken.class.isAssignableFrom(authentication)); } //後續權限控制 // private Set<GrantedAuthority> listUserGrantedAuthorities(Long uid) { // Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>(); // if (null == uid) { // return authorities; // } // authorities.add(new SimpleGrantedAuthority("ROLE_USER")); // return authorities; // } }
import com.idoipo.ibt.bto.UserDetail; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Arrays; import java.util.List; /** * Created by Jemmy on 2017-09-08. */ @Component @SuppressWarnings("unused") public class LoginAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler{ private Logger logger= LoggerFactory.getLogger(LoginAuthenticationSuccessHandler.class); @Value("${com.pages.main}") private String mainUrl; @Value("${com.common.domain}") private String commonDomain; public LoginAuthenticationSuccessHandler() { super(); } @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException { logger.info("登陸用戶服務成功"); this.setDefaultTargetUrl(mainUrl); this.setAlwaysUseDefaultTargetUrl(true); UserDetail userDetail=(UserDetail)authentication.getPrincipal(); // request.setAttribute("TOKEN",userDetail.getJwtToken()); Cookie cookie=new Cookie("IBT-TOKEN",userDetail.getJwtToken()); cookie.setPath("/"); cookie.setHttpOnly(false); cookie.setDomain(commonDomain); response.addCookie(cookie); super.onAuthenticationSuccess(request, response, authentication); //request.getRequestDispatcher("redirect:/main").forward(request,response); } }