├── .gitignore ├── imooc-security-app ├── .gitignore ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── imooc │ └── security │ └── app │ ├── ImoocAuthorizationServerConfig.java │ ├── ImoocResourceServerConfig.java │ ├── TokenStoreConfig.java │ ├── authentication │ ├── ImoocAuthenticationFailureHandler.java │ └── ImoocAuthenticationSuccessHandler.java │ ├── controller │ └── AppSecurityController.java │ ├── jwt │ └── ImoocJwtTokenEnhancer.java │ ├── social │ └── AppSocialAuthenticationFilterPostProcessor.java │ └── spring │ └── SpringSocialBeanPostProcessor.java ├── imooc-security-authorize ├── .gitignore ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── imooc │ └── security │ └── rbac │ ├── RbacService.java │ └── RbacServiceImpl.java ├── imooc-security-browser ├── .gitignore ├── pom.xml ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── imooc │ │ │ └── security │ │ │ └── browser │ │ │ ├── BrowserSearcurityCustomizableBeanConfig.java │ │ │ ├── BrowserSecurityConfig.java │ │ │ ├── authentication │ │ │ ├── ImoocAuthenticationFailureHandler.java │ │ │ └── ImoocAuthenticationSuccessHandler.java │ │ │ ├── controller │ │ │ └── BrowserSecurityController.java │ │ │ ├── logout │ │ │ └── ImoocLogoutSuccessHandler.java │ │ │ └── session │ │ │ ├── ImoocExpiredSessionStrategy.java │ │ │ └── ImoocInvalidSessionStrategy.java │ │ └── resources │ │ └── resources │ │ ├── imooc-banding.html │ │ ├── imooc-session-invalid.html │ │ ├── imooc-signin.html │ │ ├── imooc-signout.html │ │ └── imooc-signup.html └── 笔记-browser.txt ├── imooc-security-core ├── .gitignore ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── imooc │ └── security │ └── core │ ├── CoreSecurityConfig.java │ ├── CoreSecurityCustomiableBeanConfig.java │ ├── authentication │ ├── mobile │ │ ├── SmsCodeAuthenticationFilter.java │ │ ├── SmsCodeAuthenticationProvider.java │ │ ├── SmsCodeAuthenticationSecurityConfig.java │ │ └── SmsCodeAuthenticationToken.java │ └── openid │ │ ├── OpenIdAuthenticationFilter.java │ │ ├── OpenIdAuthenticationProvider.java │ │ ├── OpenIdAuthenticationSecurityConfig.java │ │ └── OpenIdAuthenticationToken.java │ ├── authorize │ ├── AuthorizeConfigManager.java │ ├── AuthorizeConfigProvider.java │ ├── ImoocAuthorizeConfigManager.java │ └── ImoocAuthorizeConfigProvider.java │ ├── exception │ └── AppSecurityException.java │ ├── properties │ ├── AppProperties.java │ ├── BrowserProperties.java │ ├── ImageCodeProperties.java │ ├── OAuth2ClientProperties.java │ ├── OAuth2Properties.java │ ├── QQProperties.java │ ├── SecurityProperties.java │ ├── SessionProperties.java │ ├── SmsCodeProperties.java │ ├── SocialProperties.java │ ├── ValidateCodeProperties.java │ ├── WeixinProperties.java │ └── contsant │ │ ├── AuthenticationResponseTypeEnum.java │ │ ├── SecurityConstants.java │ │ └── ValidateCodeTypeEnum.java │ ├── social │ ├── AppSignupUtils.java │ ├── ImoocSpringSocialConfigurer.java │ ├── SocialAuthenticationFilterPostProcessor.java │ ├── SocialConfig.java │ ├── qq │ │ ├── api │ │ │ ├── QQ.java │ │ │ ├── QQImpl.java │ │ │ └── QQUserInfo.java │ │ ├── config │ │ │ └── QQAutoConfig.java │ │ └── connect │ │ │ ├── QQAdapter.java │ │ │ ├── QQConnectionFactory.java │ │ │ ├── QQOAuth2Template.java │ │ │ └── QQServiceProvider.java │ ├── view │ │ ├── ImoocConnecStatusView.java │ │ └── ImoocConnectedView.java │ └── weixin │ │ └── api │ │ ├── Weixin.java │ │ ├── WeixinImpl.java │ │ └── WeixinUserInfo.java │ ├── support │ ├── SimpleResponse.java │ └── SocialUserInfo.java │ └── validate │ └── code │ ├── AbstractValidateCodeProcessor.java │ ├── HttpSessionValidateCodeRepository.java │ ├── RedisValidateCodeRepository.java │ ├── ValidateCode.java │ ├── ValidateCodeController.java │ ├── ValidateCodeException.java │ ├── ValidateCodeFilter.java │ ├── ValidateCodeGenerator.java │ ├── ValidateCodeProcessor.java │ ├── ValidateCodeRepository.java │ ├── ValidateCodeSecurityConfig.java │ ├── image │ ├── DefaultImageCodeGenerator.java │ ├── ImageCode.java │ ├── ImageCodeGenerator.java │ └── ImageCodeProcessor.java │ └── sms │ ├── DefaultSmsCodeGenerator.java │ ├── DefaultSmsCodeSender.java │ ├── SmsCode.java │ ├── SmsCodeGenerator.java │ ├── SmsCodeProcessor.java │ └── SmsCodeSender.java ├── imooc-security-demo ├── .gitignore ├── pom.xml ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── imooc │ │ │ │ ├── DemoApplication.java │ │ │ │ ├── authentication │ │ │ │ ├── DemoAuthenticationFailureHandler.java │ │ │ │ └── DemoAuthenticationSuccessHandler.java │ │ │ │ ├── authorize │ │ │ │ └── DemoAuthroizeConfigProvider.java │ │ │ │ ├── dto │ │ │ │ ├── FileInfo.java │ │ │ │ ├── User.java │ │ │ │ └── UserQueryCondition.java │ │ │ │ ├── exception │ │ │ │ └── UserNotExistException.java │ │ │ │ ├── security │ │ │ │ ├── DemoConnectionSignUp.java │ │ │ │ └── MyUserDetailsService.java │ │ │ │ ├── service │ │ │ │ ├── HelloService.java │ │ │ │ └── impl │ │ │ │ │ └── HelloServiceImpl.java │ │ │ │ ├── social │ │ │ │ └── qq │ │ │ │ │ ├── DemoConnectedView.java │ │ │ │ │ └── DemoStatusView.java │ │ │ │ ├── validator │ │ │ │ ├── MyConstraint.java │ │ │ │ └── MyConstraintValidator.java │ │ │ │ ├── web │ │ │ │ ├── aspect │ │ │ │ │ └── TimeAspect.java │ │ │ │ ├── async │ │ │ │ │ ├── AsyncController.java │ │ │ │ │ ├── DeferredResultHolder.java │ │ │ │ │ ├── MockQueue.java │ │ │ │ │ └── QueueListener.java │ │ │ │ ├── config │ │ │ │ │ └── WebConfig.java │ │ │ │ ├── controller │ │ │ │ │ ├── ControllerExceptionHandler.java │ │ │ │ │ ├── FileController.java │ │ │ │ │ └── UserController.java │ │ │ │ ├── filter │ │ │ │ │ └── TimeFilter.java │ │ │ │ └── interceptor │ │ │ │ │ └── TimeInterceptor.java │ │ │ │ └── wiremock │ │ │ │ └── MockServer.java │ │ └── resources │ │ │ ├── application.properties │ │ │ └── resources │ │ │ ├── demo-banding.html │ │ │ ├── demo-signin.html │ │ │ ├── demo-signout.html │ │ │ ├── demo-signup.html │ │ │ ├── error │ │ │ ├── 404.html │ │ │ └── 500.html │ │ │ └── index.html │ └── test │ │ └── java │ │ └── com │ │ └── imooc │ │ └── web │ │ └── controller │ │ ├── FileControllerTest.java │ │ └── UserControllerTest.java └── 笔记-demo.txt ├── pom.xml └── spring security核心知识点截图 ├── 01、SpringSecurity过滤器链原理.JPG ├── 02、SpringSecurity认证流程核心类、.JPG ├── 03、RememberMe功能流程.JPG ├── 04、Oauth所要解决的问题.JPG ├── 05、Oauth中的角色.和抽象的操作交互流程.JPG ├── 06、Oauth的四种用户授权模式.JPG ├── 07、Oauth授权码模式流程.JPG ├── 08、Spring Social模块介绍.JPG ├── 09、Spring Social认认证流程核心类.JPG ├── 10、Spring Security OAuth开发第三方应用认证框架.JPG ├── 11、Spring Security OAuth2核心源码.JPG ├── 12、用Spring Security OAuth2重构APP 图片验证码和短信验证码登陆.JPG ├── 13、用Spring Security OAuth2 重构APP 社交授权码授权模式登陆.JPG ├── 13、用Spring Security OAuth2 重构APP 社交简化授权模式登陆.JPG ├── 14、jwt的特点.JPG └── spring security过滤器一览.png /.gitignore: -------------------------------------------------------------------------------- 1 | # eclipse 项目文件 2 | .settings 3 | .classpath 4 | .project 5 | 6 | # idea 项目文件 7 | .idea 8 | *.*iml 9 | 10 | # 编译文件 11 | /target/ 12 | /bin/ 13 | 14 | # spring boot本地配置文件 15 | application-local.yml 16 | application-local.properties 17 | -------------------------------------------------------------------------------- /imooc-security-app/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | 3 | /.apt_generated/ 4 | 5 | 6 | .factorypath -------------------------------------------------------------------------------- /imooc-security-app/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | imooc-security-app 5 | 6 | com.imooc.security 7 | imooc-security 8 | 0.0.1-SNAPSHOT 9 | 10 | ${imooc.security.version} 11 | 12 | 13 | 14 | com.imooc.security 15 | imooc-security-core 16 | ${imooc.security.version} 17 | 18 | 19 | -------------------------------------------------------------------------------- /imooc-security-app/src/main/java/com/imooc/security/app/ImoocAuthorizationServerConfig.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.app; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.security.authentication.AuthenticationManager; 11 | import org.springframework.security.core.userdetails.UserDetailsService; 12 | import org.springframework.security.oauth2.config.annotation.builders.InMemoryClientDetailsServiceBuilder; 13 | import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; 14 | import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; 15 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; 16 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; 17 | import org.springframework.security.oauth2.provider.token.TokenEnhancer; 18 | import org.springframework.security.oauth2.provider.token.TokenEnhancerChain; 19 | import org.springframework.security.oauth2.provider.token.TokenStore; 20 | import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; 21 | import org.springframework.security.web.authentication.AuthenticationFailureHandler; 22 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler; 23 | 24 | import com.imooc.security.app.authentication.ImoocAuthenticationFailureHandler; 25 | import com.imooc.security.app.authentication.ImoocAuthenticationSuccessHandler; 26 | import com.imooc.security.app.social.AppSocialAuthenticationFilterPostProcessor; 27 | import com.imooc.security.core.properties.OAuth2ClientProperties; 28 | import com.imooc.security.core.properties.SecurityProperties; 29 | import com.imooc.security.core.social.SocialAuthenticationFilterPostProcessor; 30 | 31 | /** 32 | * 标注为认证授权服务器 33 | * @author Administrator 34 | * 35 | */ 36 | @Configuration 37 | @EnableAuthorizationServer 38 | public class ImoocAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { 39 | 40 | @Bean 41 | @ConditionalOnMissingBean(value = AuthenticationSuccessHandler.class) 42 | public AuthenticationSuccessHandler authenticationSuccessHandler() { 43 | return new ImoocAuthenticationSuccessHandler(); 44 | } 45 | 46 | @Bean 47 | @ConditionalOnMissingBean(value = AuthenticationFailureHandler.class) 48 | public AuthenticationFailureHandler authenticationFailureHandler() { 49 | return new ImoocAuthenticationFailureHandler(); 50 | } 51 | 52 | @Bean 53 | @ConditionalOnMissingBean(value = SocialAuthenticationFilterPostProcessor.class) 54 | public SocialAuthenticationFilterPostProcessor socialAuthenticationFilterPostProcessor() { 55 | return new AppSocialAuthenticationFilterPostProcessor(); 56 | } 57 | 58 | @Autowired 59 | private AuthenticationManager authenticationManager; 60 | 61 | @Autowired 62 | private UserDetailsService userDetailsService; 63 | 64 | @Autowired 65 | private SecurityProperties securityProperties; 66 | 67 | @Autowired 68 | private TokenStore tokenStore; 69 | 70 | @Autowired(required = false) 71 | private JwtAccessTokenConverter jwtAccessTokenConverter; 72 | 73 | @Autowired(required = false) 74 | private TokenEnhancer jwtTokenEnhancer; 75 | 76 | /** 77 | * 给TokanEndpoint配置 78 | */ 79 | @Override 80 | public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { 81 | endpoints 82 | .tokenStore(tokenStore) 83 | .authenticationManager(authenticationManager) 84 | .userDetailsService(userDetailsService); 85 | 86 | if (jwtAccessTokenConverter != null && jwtTokenEnhancer != null) { 87 | TokenEnhancerChain enhancerChain = new TokenEnhancerChain(); 88 | List enhancers = new ArrayList<>(); 89 | enhancers.add(jwtTokenEnhancer); 90 | enhancers.add(jwtAccessTokenConverter); 91 | enhancerChain.setTokenEnhancers(enhancers); 92 | 93 | endpoints 94 | .tokenEnhancer(enhancerChain) 95 | .accessTokenConverter(jwtAccessTokenConverter); 96 | } 97 | } 98 | 99 | /** 100 | * 101 | * 决定能给哪些clientId, clientSecret发令牌 102 | */ 103 | @Override 104 | public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 105 | InMemoryClientDetailsServiceBuilder builder = clients.inMemory(); 106 | for (OAuth2ClientProperties config : securityProperties.getOauth2().getClients()) { 107 | builder.withClient(config.getClientId()) 108 | .secret(config.getClientSecret()) 109 | .accessTokenValiditySeconds(config.getAccessTokenValiditySeconds()) 110 | .authorizedGrantTypes("refresh_token", "password") 111 | .scopes("all", "read", "write"); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /imooc-security-app/src/main/java/com/imooc/security/app/ImoocResourceServerConfig.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.app; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 8 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 9 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 10 | import org.springframework.security.web.authentication.AuthenticationFailureHandler; 11 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler; 12 | import org.springframework.social.security.SpringSocialConfigurer; 13 | 14 | import com.imooc.security.core.authentication.mobile.SmsCodeAuthenticationSecurityConfig; 15 | import com.imooc.security.core.authentication.openid.OpenIdAuthenticationSecurityConfig; 16 | import com.imooc.security.core.authorize.AuthorizeConfigManager; 17 | import com.imooc.security.core.properties.SecurityProperties; 18 | import com.imooc.security.core.validate.code.RedisValidateCodeRepository; 19 | import com.imooc.security.core.validate.code.ValidateCodeRepository; 20 | import com.imooc.security.core.validate.code.ValidateCodeSecurityConfig; 21 | 22 | /** 23 | * 标注为资源服务器 24 | * @author Administrator 25 | * 26 | */ 27 | @Configuration 28 | @EnableResourceServer 29 | public class ImoocResourceServerConfig extends ResourceServerConfigurerAdapter { 30 | 31 | @Autowired 32 | private SecurityProperties securityProperties; 33 | 34 | @Autowired 35 | private ValidateCodeSecurityConfig validateCodeSecurityConfig; 36 | 37 | @Autowired 38 | private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig; 39 | 40 | @Autowired 41 | private SpringSocialConfigurer imoocSocialSecurityConfig; 42 | 43 | @Autowired 44 | private OpenIdAuthenticationSecurityConfig openIdAuthenticationSecurityConfig; 45 | 46 | @Autowired 47 | private AuthenticationSuccessHandler authenticationSuccessHandler; 48 | 49 | @Autowired 50 | private AuthenticationFailureHandler authenticationFailureHandler; 51 | 52 | @Autowired 53 | private AuthorizeConfigManager authorizeConfigManager; 54 | 55 | @Bean 56 | @ConditionalOnMissingBean(value = ValidateCodeRepository.class) 57 | public ValidateCodeRepository validateCodeRepository() { 58 | return new RedisValidateCodeRepository(); 59 | } 60 | 61 | @Override 62 | public void configure(HttpSecurity http) throws Exception { 63 | 64 | http 65 | // 验证码校验相关配置 66 | .apply(validateCodeSecurityConfig) 67 | .and() 68 | // 验证码登陆相关配置 69 | .apply(smsCodeAuthenticationSecurityConfig) 70 | .and() 71 | // browser social登陆相关配置 72 | .apply(imoocSocialSecurityConfig) 73 | .and() 74 | // app social登陆相关配置 75 | .apply(openIdAuthenticationSecurityConfig) 76 | .and() 77 | // 表单登陆相关配置 78 | .formLogin() 79 | .loginPage(securityProperties.getBrowser().getUnAuthenticationUrl()) //表单登陆URL 80 | .loginProcessingUrl(securityProperties.getBrowser().getSigninProcessUrlForm()) //处理登陆请求的URL 81 | .successHandler(authenticationSuccessHandler) // 登陆成功处理器 82 | .failureHandler(authenticationFailureHandler) // 登陆失败处理器 83 | .and() 84 | // 退出登陆相关配置 85 | // .logout() 86 | // // 退出登陆的动作 87 | // .logoutUrl(securityProperties.getBrowser().getSignoutUrl()) 88 | // .logoutSuccessUrl(securityProperties.getBrowser().getSignoutSuccessUrl()) 89 | // // 退出成功后的重定向地址,logoutSuccessHandler与logoutSuccessUrl互斥, 若配置该项,logoutSuccessUrl配置将失效, 不过handler可以通过该配置逻辑控制 90 | // .logoutSuccessHandler(logoutSuccessHandler) 91 | // .deleteCookies(securityProperties.getBrowser().getSignoutDeleteCookies()) 92 | // .and() 93 | // 记住我 94 | // .rememberMe() 95 | // .tokenRepository(persistentTokenRepository()) 96 | // .tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds()) 97 | // .userDetailsService(userDetailsService) 98 | // .and() 99 | // session配置 100 | // .sessionManagement() 101 | // // session失效时的重定向地址 102 | //// .invalidSessionUrl(securityProperties.getBrowser().getSession().getSessionInvalidRedirectUrl()) 103 | // // session失效的处理器, 此项设置了的话,invalidSessionUrl将失效 104 | // .invalidSessionStrategy(invalidSessionStrategy) 105 | // // 同一用户最多产生的session数 106 | // .maximumSessions(securityProperties.getBrowser().getSession().getMaxinumSession()) 107 | // // 如果超出最大session限制, 则阻止登陆 108 | // .maxSessionsPreventsLogin(securityProperties.getBrowser().getSession().isMaxSessionsPreventsLogin()) 109 | // // session被踢出时的处理器 110 | // .expiredSessionStrategy(sessionInformationExpiredStrategy) 111 | // .and() 112 | // .and() 113 | // csrf配置 114 | .csrf() 115 | .disable(); 116 | 117 | authorizeConfigManager.config(http.authorizeRequests()); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /imooc-security-app/src/main/java/com/imooc/security/app/TokenStoreConfig.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.app; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.data.redis.connection.RedisConnectionFactory; 9 | import org.springframework.security.oauth2.provider.token.TokenEnhancer; 10 | import org.springframework.security.oauth2.provider.token.TokenStore; 11 | import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; 12 | import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; 13 | import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore; 14 | 15 | import com.imooc.security.app.jwt.ImoocJwtTokenEnhancer; 16 | import com.imooc.security.core.properties.SecurityProperties; 17 | 18 | @Configuration 19 | public class TokenStoreConfig { 20 | 21 | @Autowired 22 | private RedisConnectionFactory redisConnectionFactory; 23 | 24 | @Bean 25 | @ConditionalOnProperty(prefix="imooc.security.oauth2", name="store-type", havingValue="redis") 26 | public TokenStore redisTokenStore() { 27 | return new RedisTokenStore(redisConnectionFactory); 28 | } 29 | 30 | @Configuration 31 | @ConditionalOnProperty(prefix="imooc.security.oauth2", name="store-type", havingValue="jwt", matchIfMissing=true) 32 | public static class JwtTokenConfig { 33 | 34 | @Autowired 35 | private SecurityProperties securityProperties; 36 | 37 | @Bean 38 | public TokenStore jwtTokenStore() { 39 | return new JwtTokenStore(jwtAccessTokenConverter()); 40 | } 41 | 42 | /** 43 | * 转换器, 设置jwt密签key 44 | * @return 45 | */ 46 | @Bean 47 | public JwtAccessTokenConverter jwtAccessTokenConverter() { 48 | JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); 49 | converter.setSigningKey(securityProperties.getOauth2().getSigningKey()); 50 | return converter; 51 | } 52 | 53 | @Bean 54 | @ConditionalOnMissingBean(name = "jwtTokenEnhancer") 55 | public TokenEnhancer jwtTokenEnhancer() { 56 | return new ImoocJwtTokenEnhancer(); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /imooc-security-app/src/main/java/com/imooc/security/app/authentication/ImoocAuthenticationFailureHandler.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.app.authentication; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.ServletException; 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.http.HttpStatus; 13 | import org.springframework.security.core.AuthenticationException; 14 | import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; 15 | 16 | import com.fasterxml.jackson.databind.ObjectMapper; 17 | import com.imooc.security.core.properties.SecurityProperties; 18 | import com.imooc.security.core.properties.contsant.AuthenticationResponseTypeEnum; 19 | 20 | public class ImoocAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { 21 | 22 | private Logger logger = LoggerFactory.getLogger(getClass()); 23 | 24 | /** 25 | * spring启动的时候会自动注册 26 | */ 27 | @Autowired 28 | private ObjectMapper objectMapper; 29 | 30 | @Autowired 31 | private SecurityProperties securityProperties; 32 | 33 | @Override 34 | public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, 35 | AuthenticationException exception) throws IOException, ServletException { 36 | 37 | logger.info("imooc登陆失败"); 38 | 39 | if (AuthenticationResponseTypeEnum.JSON.equals(securityProperties.getBrowser().getAuthentionResponseType())) { 40 | response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); 41 | response.setContentType("application/json;charset=UTF-8"); 42 | response.getWriter().write(objectMapper.writeValueAsString(exception.getMessage())); 43 | } else if (AuthenticationResponseTypeEnum.DIRECT.equals(securityProperties.getBrowser().getAuthentionResponseType())) { 44 | logger.error(exception.getMessage()); 45 | super.onAuthenticationFailure(request, response, exception); 46 | } 47 | 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /imooc-security-app/src/main/java/com/imooc/security/app/authentication/ImoocAuthenticationSuccessHandler.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.app.authentication; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.ServletException; 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | 9 | import org.apache.commons.collections.MapUtils; 10 | import org.apache.commons.lang.StringUtils; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.security.authentication.BadCredentialsException; 15 | import org.springframework.security.core.Authentication; 16 | import org.springframework.security.crypto.codec.Base64; 17 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 18 | import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException; 19 | import org.springframework.security.oauth2.provider.ClientDetails; 20 | import org.springframework.security.oauth2.provider.ClientDetailsService; 21 | import org.springframework.security.oauth2.provider.OAuth2Authentication; 22 | import org.springframework.security.oauth2.provider.OAuth2Request; 23 | import org.springframework.security.oauth2.provider.TokenRequest; 24 | import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; 25 | import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; 26 | 27 | import com.fasterxml.jackson.databind.ObjectMapper; 28 | import com.imooc.security.core.properties.SecurityProperties; 29 | 30 | public class ImoocAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler { 31 | 32 | private Logger logger = LoggerFactory.getLogger(getClass()); 33 | 34 | /** 35 | * spring启动的时候会自动注册 36 | */ 37 | @Autowired 38 | private ObjectMapper objectMapper; 39 | 40 | @Autowired 41 | private SecurityProperties securityProperties; 42 | 43 | @Autowired 44 | private ClientDetailsService clientDetailService; 45 | 46 | @Autowired 47 | private AuthorizationServerTokenServices authorizationServerTokenServices; 48 | 49 | /** 50 | * Authentication是spring security的核心接口,封装了认证信息 51 | */ 52 | @Override 53 | public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, 54 | Authentication authentication) throws IOException, ServletException { 55 | 56 | String header = request.getHeader("Authorization"); 57 | 58 | if (header == null || !header.startsWith("Basic ")) { 59 | throw new UnapprovedClientAuthenticationException("请求头无clien信息"); 60 | } 61 | 62 | String[] tokens = extractAndDecodeHeader(header, request); 63 | assert tokens.length == 2; 64 | 65 | String clientId = tokens[0]; 66 | String clientSecret = tokens[1]; 67 | 68 | ClientDetails clientDetails = clientDetailService.loadClientByClientId(clientId); 69 | 70 | if (clientDetails == null) { 71 | throw new UnapprovedClientAuthenticationException("clientId对应的配置信息不存在" + clientId); 72 | } else if (!StringUtils.equals(clientDetails.getClientSecret(), clientSecret)) { 73 | throw new UnapprovedClientAuthenticationException("clientSecret不匹配" + clientId); 74 | } 75 | 76 | @SuppressWarnings("unchecked") 77 | TokenRequest tokenRequest = new TokenRequest(MapUtils.EMPTY_MAP, clientId, clientDetails.getScope(), "custom"); 78 | 79 | OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails); 80 | 81 | OAuth2Authentication oauth2Authentication = new OAuth2Authentication(oAuth2Request, authentication); 82 | OAuth2AccessToken oauth2AccessToken = authorizationServerTokenServices.createAccessToken(oauth2Authentication); 83 | 84 | response.setContentType("application/json;charset=UTF-8"); 85 | response.getWriter().write(objectMapper.writeValueAsString(oauth2AccessToken)); 86 | } 87 | 88 | /** 89 | * Decodes the header into a username and password. 90 | * 91 | * @throws BadCredentialsException if the Basic header is not present or is not valid 92 | * Base64 93 | */ 94 | private String[] extractAndDecodeHeader(String header, HttpServletRequest request) 95 | throws IOException { 96 | 97 | byte[] base64Token = header.substring(6).getBytes("UTF-8"); 98 | byte[] decoded; 99 | try { 100 | decoded = Base64.decode(base64Token); 101 | } 102 | catch (IllegalArgumentException e) { 103 | throw new BadCredentialsException( 104 | "Failed to decode basic authentication token"); 105 | } 106 | 107 | String token = new String(decoded, "UTF-8"); 108 | 109 | int delim = token.indexOf(":"); 110 | 111 | if (delim == -1) { 112 | throw new BadCredentialsException("Invalid basic authentication token"); 113 | } 114 | return new String[] { token.substring(0, delim), token.substring(delim + 1) }; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /imooc-security-app/src/main/java/com/imooc/security/app/controller/AppSecurityController.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.app.controller; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.social.connect.Connection; 8 | import org.springframework.social.connect.web.ProviderSignInUtils; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.ResponseStatus; 11 | import org.springframework.web.bind.annotation.RestController; 12 | import org.springframework.web.context.request.ServletWebRequest; 13 | 14 | import com.imooc.security.core.social.AppSignupUtils; 15 | import com.imooc.security.core.support.SocialUserInfo; 16 | 17 | @RestController 18 | public class AppSecurityController { 19 | 20 | @Autowired 21 | private ProviderSignInUtils providerSignInUtils; 22 | 23 | @Autowired 24 | private AppSignupUtils appSignupUtils; 25 | 26 | @GetMapping("/social/signup") 27 | @ResponseStatus(HttpStatus.UNAUTHORIZED) 28 | public SocialUserInfo getSocialUserInfo(HttpServletRequest request){ 29 | SocialUserInfo userInfo = new SocialUserInfo(); 30 | Connection connection = providerSignInUtils.getConnectionFromSession(new ServletWebRequest(request)); 31 | 32 | if (connection != null) { 33 | userInfo.setProviderId(connection.getKey().getProviderId()); 34 | userInfo.setProviderUserId(connection.getKey().getProviderUserId()); 35 | userInfo.setNickname(connection.getDisplayName()); 36 | userInfo.setHeadimg(connection.getImageUrl()); 37 | appSignupUtils.saveConnectionData(new ServletWebRequest(request), connection.createData()); 38 | } 39 | 40 | return userInfo; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /imooc-security-app/src/main/java/com/imooc/security/app/jwt/ImoocJwtTokenEnhancer.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.app.jwt; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; 7 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 8 | import org.springframework.security.oauth2.provider.OAuth2Authentication; 9 | import org.springframework.security.oauth2.provider.token.TokenEnhancer; 10 | 11 | public class ImoocJwtTokenEnhancer implements TokenEnhancer { 12 | 13 | @Override 14 | public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { 15 | Map info = new HashMap<>(); 16 | info.put("company", "imooc"); 17 | 18 | ((DefaultOAuth2AccessToken)accessToken).setAdditionalInformation(info); 19 | return accessToken; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /imooc-security-app/src/main/java/com/imooc/security/app/social/AppSocialAuthenticationFilterPostProcessor.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.app.social; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler; 5 | import org.springframework.social.security.SocialAuthenticationFilter; 6 | 7 | import com.imooc.security.core.social.SocialAuthenticationFilterPostProcessor; 8 | 9 | public class AppSocialAuthenticationFilterPostProcessor implements SocialAuthenticationFilterPostProcessor { 10 | 11 | @Autowired 12 | private AuthenticationSuccessHandler authenticationSuccessHandler; 13 | 14 | @Override 15 | public void process(SocialAuthenticationFilter socialAuthenticationFilter) { 16 | socialAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler); 17 | } 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /imooc-security-app/src/main/java/com/imooc/security/app/spring/SpringSocialBeanPostProcessor.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.app.spring; 2 | 3 | import org.apache.commons.lang.StringUtils; 4 | import org.springframework.beans.BeansException; 5 | import org.springframework.beans.factory.config.BeanPostProcessor; 6 | import org.springframework.stereotype.Component; 7 | 8 | import com.imooc.security.core.social.ImoocSpringSocialConfigurer; 9 | 10 | /** 11 | * 所有bean初始化前后都会经过这个类的方法 12 | * @author Administrator 13 | * 14 | */ 15 | @Component 16 | public class SpringSocialBeanPostProcessor implements BeanPostProcessor { 17 | 18 | @Override 19 | public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 20 | return bean; 21 | } 22 | 23 | @Override 24 | public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 25 | if (StringUtils.equals(beanName, "imoocSocialSecurityConfig")) { 26 | ImoocSpringSocialConfigurer configurer = (ImoocSpringSocialConfigurer) bean; 27 | //三方用户openid不存在于user_connection表时,重定向的路径 28 | configurer.signupUrl("/social/signup"); 29 | return configurer; 30 | } 31 | return bean; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /imooc-security-authorize/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | 3 | /.apt_generated/ 4 | 5 | 6 | .factorypath -------------------------------------------------------------------------------- /imooc-security-authorize/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | imooc-security-authorize 5 | 6 | com.imooc.security 7 | imooc-security 8 | 0.0.1-SNAPSHOT 9 | 10 | ${imooc.security.version} 11 | 12 | 13 | 14 | javax.servlet 15 | javax.servlet-api 16 | 17 | 18 | org.springframework.security 19 | spring-security-core 20 | 21 | 22 | -------------------------------------------------------------------------------- /imooc-security-authorize/src/main/java/com/imooc/security/rbac/RbacService.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.rbac; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | 5 | import org.springframework.security.core.Authentication; 6 | 7 | public interface RbacService { 8 | 9 | boolean hasPermission(HttpServletRequest request, Authentication authentication); 10 | } 11 | -------------------------------------------------------------------------------- /imooc-security-authorize/src/main/java/com/imooc/security/rbac/RbacServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.rbac; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | import javax.servlet.http.HttpServletRequest; 7 | 8 | import org.springframework.security.core.Authentication; 9 | import org.springframework.security.core.userdetails.UserDetails; 10 | import org.springframework.stereotype.Component; 11 | import org.springframework.util.AntPathMatcher; 12 | 13 | @Component("rbacService") 14 | public class RbacServiceImpl implements RbacService { 15 | 16 | private AntPathMatcher antPathMatcher = new AntPathMatcher(); 17 | 18 | @Override 19 | public boolean hasPermission(HttpServletRequest request, Authentication authentication) { 20 | Object principle = authentication.getPrincipal(); 21 | boolean hasPermission = false; 22 | if (principle instanceof UserDetails) { 23 | String username = ((UserDetails)principle).getUsername(); 24 | 25 | /** 26 | * @TODO 根据username读取用户所拥有权限的所有url 27 | */ 28 | Set urls = new HashSet<>(); 29 | for (String url : urls) { 30 | if (antPathMatcher.match(url, request.getRequestURI())) { 31 | hasPermission = true; 32 | break; 33 | } 34 | } 35 | } 36 | return hasPermission; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /imooc-security-browser/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | 3 | /.apt_generated/ 4 | 5 | 6 | .factorypath -------------------------------------------------------------------------------- /imooc-security-browser/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | imooc-security-browser 5 | 6 | com.imooc.security 7 | imooc-security 8 | 0.0.1-SNAPSHOT 9 | 10 | ${imooc.security.version} 11 | 12 | 13 | 14 | com.imooc.security 15 | imooc-security-core 16 | ${imooc.security.version} 17 | 18 | 19 | org.springframework.session 20 | spring-session 21 | 22 | 27 | 28 | -------------------------------------------------------------------------------- /imooc-security-browser/src/main/java/com/imooc/security/browser/BrowserSearcurityCustomizableBeanConfig.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.browser; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.security.web.authentication.AuthenticationFailureHandler; 8 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler; 9 | import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; 10 | import org.springframework.security.web.session.InvalidSessionStrategy; 11 | import org.springframework.security.web.session.SessionInformationExpiredStrategy; 12 | 13 | import com.imooc.security.browser.authentication.ImoocAuthenticationSuccessHandler; 14 | import com.imooc.security.browser.authentication.ImoocAuthenticationFailureHandler; 15 | import com.imooc.security.browser.logout.ImoocLogoutSuccessHandler; 16 | import com.imooc.security.browser.session.ImoocExpiredSessionStrategy; 17 | import com.imooc.security.browser.session.ImoocInvalidSessionStrategy; 18 | import com.imooc.security.core.properties.SecurityProperties; 19 | import com.imooc.security.core.validate.code.HttpSessionValidateCodeRepository; 20 | import com.imooc.security.core.validate.code.ValidateCodeRepository; 21 | 22 | /** 23 | * 此处配置可被使用者定制替换的bean 24 | * @author lizhuquan 25 | * 26 | */ 27 | @Configuration 28 | public class BrowserSearcurityCustomizableBeanConfig { 29 | 30 | @Autowired 31 | private SecurityProperties securityProperties; 32 | 33 | @Bean 34 | @ConditionalOnMissingBean(value = AuthenticationSuccessHandler.class) 35 | public AuthenticationSuccessHandler authenticationSuccessHandler() { 36 | return new ImoocAuthenticationSuccessHandler(); 37 | } 38 | 39 | @Bean 40 | @ConditionalOnMissingBean(value = AuthenticationFailureHandler.class) 41 | public AuthenticationFailureHandler authenticationFailureHandler() { 42 | return new ImoocAuthenticationFailureHandler(); 43 | } 44 | 45 | @Bean 46 | @ConditionalOnMissingBean(value = SessionInformationExpiredStrategy.class) 47 | public SessionInformationExpiredStrategy sessionInformationExpiredStrategy() { 48 | return new ImoocExpiredSessionStrategy(); 49 | } 50 | 51 | @Bean 52 | @ConditionalOnMissingBean(value = InvalidSessionStrategy.class) 53 | public InvalidSessionStrategy invalidSessionStrategy() { 54 | return new ImoocInvalidSessionStrategy(securityProperties.getBrowser().getSession().getSessionInvalidRedirectUrl()); 55 | } 56 | 57 | @Bean 58 | @ConditionalOnMissingBean(value = LogoutSuccessHandler.class) 59 | public LogoutSuccessHandler logoutSuccessHandler() { 60 | return new ImoocLogoutSuccessHandler(securityProperties.getBrowser().getSignoutSuccessUrl()); 61 | } 62 | 63 | @Bean 64 | @ConditionalOnMissingBean(value = ValidateCodeRepository.class) 65 | public ValidateCodeRepository validateCodeRepository() { 66 | return new HttpSessionValidateCodeRepository(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /imooc-security-browser/src/main/java/com/imooc/security/browser/authentication/ImoocAuthenticationFailureHandler.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.browser.authentication; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.ServletException; 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.http.HttpStatus; 13 | import org.springframework.security.core.AuthenticationException; 14 | import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; 15 | 16 | import com.fasterxml.jackson.databind.ObjectMapper; 17 | import com.imooc.security.core.properties.SecurityProperties; 18 | import com.imooc.security.core.properties.contsant.AuthenticationResponseTypeEnum; 19 | 20 | public class ImoocAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { 21 | 22 | private Logger logger = LoggerFactory.getLogger(getClass()); 23 | 24 | /** 25 | * spring启动的时候会自动注册 26 | */ 27 | @Autowired 28 | private ObjectMapper objectMapper; 29 | 30 | @Autowired 31 | private SecurityProperties securityProperties; 32 | 33 | @Override 34 | public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, 35 | AuthenticationException exception) throws IOException, ServletException { 36 | 37 | logger.info("imooc登陆失败"); 38 | 39 | if (AuthenticationResponseTypeEnum.JSON.equals(securityProperties.getBrowser().getAuthentionResponseType())) { 40 | response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); 41 | response.setContentType("application/json;charset=UTF-8"); 42 | response.getWriter().write(objectMapper.writeValueAsString(exception.getMessage())); 43 | } else if (AuthenticationResponseTypeEnum.DIRECT.equals(securityProperties.getBrowser().getAuthentionResponseType())) { 44 | logger.error(exception.getMessage()); 45 | super.onAuthenticationFailure(request, response, exception); 46 | } 47 | 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /imooc-security-browser/src/main/java/com/imooc/security/browser/authentication/ImoocAuthenticationSuccessHandler.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.browser.authentication; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.ServletException; 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.security.core.Authentication; 13 | import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; 14 | 15 | import com.fasterxml.jackson.databind.ObjectMapper; 16 | import com.imooc.security.core.properties.SecurityProperties; 17 | import com.imooc.security.core.properties.contsant.AuthenticationResponseTypeEnum; 18 | 19 | public class ImoocAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler { 20 | 21 | private Logger logger = LoggerFactory.getLogger(getClass()); 22 | 23 | /** 24 | * spring启动的时候会自动注册 25 | */ 26 | @Autowired 27 | private ObjectMapper objectMapper; 28 | 29 | @Autowired 30 | private SecurityProperties securityProperties; 31 | 32 | /** 33 | * Authentication是spring security的核心接口,封装了认证信息 34 | */ 35 | @Override 36 | public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, 37 | Authentication authentication) throws IOException, ServletException { 38 | 39 | logger.info("imooc登陆成功"); 40 | 41 | if (AuthenticationResponseTypeEnum.JSON.equals(securityProperties.getBrowser().getAuthentionResponseType())) { 42 | response.setContentType("application/json;charset=UTF-8"); 43 | response.getWriter().write(objectMapper.writeValueAsString(authentication)); 44 | } else if (AuthenticationResponseTypeEnum.DIRECT.equals(securityProperties.getBrowser().getAuthentionResponseType())) { 45 | // 跳转 46 | super.onAuthenticationSuccess(request, response, authentication); 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /imooc-security-browser/src/main/java/com/imooc/security/browser/controller/BrowserSecurityController.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.browser.controller; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | 8 | import org.apache.commons.lang.StringUtils; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.http.HttpStatus; 11 | import org.springframework.security.core.Authentication; 12 | import org.springframework.security.core.annotation.AuthenticationPrincipal; 13 | import org.springframework.security.core.userdetails.UserDetails; 14 | import org.springframework.security.web.DefaultRedirectStrategy; 15 | import org.springframework.security.web.RedirectStrategy; 16 | import org.springframework.security.web.savedrequest.HttpSessionRequestCache; 17 | import org.springframework.security.web.savedrequest.RequestCache; 18 | import org.springframework.security.web.savedrequest.SavedRequest; 19 | import org.springframework.social.connect.Connection; 20 | import org.springframework.social.connect.web.ProviderSignInUtils; 21 | import org.springframework.web.bind.annotation.GetMapping; 22 | import org.springframework.web.bind.annotation.RequestMapping; 23 | import org.springframework.web.bind.annotation.ResponseStatus; 24 | import org.springframework.web.bind.annotation.RestController; 25 | import org.springframework.web.context.request.ServletWebRequest; 26 | 27 | import com.imooc.security.core.properties.SecurityProperties; 28 | import com.imooc.security.core.support.SimpleResponse; 29 | import com.imooc.security.core.support.SocialUserInfo; 30 | 31 | @RestController 32 | public class BrowserSecurityController { 33 | 34 | // 重定向到身份验证url前, 会在Session塞一个SavedRequest对象(具体可查看源码ExceptionTranslationFilter.sendStartAuthentication方法), 35 | // 通过RequestCache.getRequest()可获取到 36 | private RequestCache requestCache = new HttpSessionRequestCache(); 37 | 38 | // 工具类,方便拼装重定向url 39 | private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); 40 | 41 | @Autowired 42 | private SecurityProperties securityProperties; 43 | 44 | /** 45 | * 该工具是基于http session 46 | */ 47 | @Autowired 48 | private ProviderSignInUtils providerSignInUtils; 49 | 50 | /** 51 | * 当没身份校验时的登陆调试跳转逻辑 52 | * @param request 53 | * @param response 54 | * @return 55 | * @throws IOException 56 | */ 57 | @RequestMapping("#{globalSecurityProperties.browser.unAuthenticationUrl}") 58 | @ResponseStatus(code = HttpStatus.UNAUTHORIZED) 59 | public SimpleResponse requireAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authenction) throws IOException { 60 | SavedRequest savedRequest = requestCache.getRequest(request, response); 61 | 62 | boolean auth = authenction != null && authenction.isAuthenticated(); 63 | boolean hasBackUrl = savedRequest != null; 64 | 65 | if (auth) { 66 | return new SimpleResponse("你已登录成功, 请自行游览"); 67 | } else { 68 | if (hasBackUrl) { 69 | String targetUrl = savedRequest.getRedirectUrl(); 70 | if (StringUtils.endsWithIgnoreCase(targetUrl, ".html")) { 71 | // 如果是页面请求, 重定向回去 72 | redirectStrategy.sendRedirect(request, response, securityProperties.getBrowser().getSigninPageUrl()); 73 | return null; 74 | } 75 | 76 | } 77 | return new SimpleResponse("访问的服务需要身份验证, 请引导用户到登陆页"); 78 | } 79 | } 80 | 81 | /** 82 | * 查看已绑定用户 83 | * @param request 84 | * @return 85 | */ 86 | @GetMapping("/social/user") 87 | public SocialUserInfo getSocialInfo(HttpServletRequest request) { 88 | SocialUserInfo userInfo = new SocialUserInfo(); 89 | Connection connection = providerSignInUtils.getConnectionFromSession(new ServletWebRequest(request)); 90 | 91 | if (connection != null) { 92 | userInfo.setProviderId(connection.getKey().getProviderId()); 93 | userInfo.setProviderUserId(connection.getKey().getProviderUserId()); 94 | userInfo.setNickname(connection.getDisplayName()); 95 | userInfo.setHeadimg(connection.getImageUrl()); 96 | } 97 | 98 | return userInfo; 99 | } 100 | 101 | @GetMapping("/me") 102 | public Object getCurrentUser(@AuthenticationPrincipal UserDetails user) { 103 | return user; 104 | } 105 | 106 | @GetMapping("#{globalSecurityProperties.browser.session.sessionInvalidRedirectUrl}") 107 | @ResponseStatus(HttpStatus.UNAUTHORIZED) 108 | public SimpleResponse sessionInvalid(HttpServletRequest request, HttpServletResponse response) throws IOException { 109 | String message = "session失效哦, /session/invalid"; 110 | return new SimpleResponse(message); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /imooc-security-browser/src/main/java/com/imooc/security/browser/logout/ImoocLogoutSuccessHandler.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.browser.logout; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.ServletException; 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | 9 | import org.apache.commons.lang.StringUtils; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | import org.springframework.security.core.Authentication; 13 | import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; 14 | 15 | import com.fasterxml.jackson.databind.ObjectMapper; 16 | import com.imooc.security.core.properties.contsant.SecurityConstants; 17 | import com.imooc.security.core.support.SimpleResponse; 18 | 19 | public class ImoocLogoutSuccessHandler implements LogoutSuccessHandler { 20 | 21 | private Logger logger = LoggerFactory.getLogger(getClass()); 22 | 23 | private ObjectMapper objectMapper = new ObjectMapper(); 24 | 25 | private String logoutSuccessUrl; 26 | 27 | public ImoocLogoutSuccessHandler(String logoutSuccessUrl) { 28 | this.logoutSuccessUrl = logoutSuccessUrl; 29 | } 30 | 31 | @Override 32 | public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) 33 | throws IOException, ServletException { 34 | 35 | logger.info("退出成功"); 36 | 37 | if (!StringUtils.isBlank(logoutSuccessUrl) && !SecurityConstants.DEFAULT_SIGNOUT_SUCCESS_URL.equals(logoutSuccessUrl)) { 38 | response.sendRedirect(logoutSuccessUrl); 39 | } else { 40 | response.setContentType("application/json;charset=UTF-8"); 41 | response.getWriter().write(objectMapper.writeValueAsString(new SimpleResponse("退出成功"))); 42 | } 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /imooc-security-browser/src/main/java/com/imooc/security/browser/session/ImoocExpiredSessionStrategy.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.browser.session; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.ServletException; 6 | import javax.servlet.http.HttpServletResponse; 7 | 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.security.web.session.SessionInformationExpiredEvent; 11 | import org.springframework.security.web.session.SessionInformationExpiredStrategy; 12 | 13 | public class ImoocExpiredSessionStrategy implements SessionInformationExpiredStrategy { 14 | 15 | private Logger logger = LoggerFactory.getLogger(getClass()); 16 | 17 | @Override 18 | public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException { 19 | Object principal = event.getSessionInformation().getPrincipal(); 20 | logger.info("用户" + principal + "由于并发登陆被踢下了"); 21 | 22 | HttpServletResponse response = event.getResponse(); 23 | response.setContentType("text/plain;charset=UTF-8"); 24 | response.getWriter().write("你的帐号在别的地方登陆了, 你已被挤下线"); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /imooc-security-browser/src/main/java/com/imooc/security/browser/session/ImoocInvalidSessionStrategy.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.imooc.security.browser.session; 5 | 6 | import java.io.IOException; 7 | 8 | import javax.servlet.ServletException; 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | 12 | import org.apache.commons.lang.StringUtils; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | import org.springframework.http.HttpStatus; 16 | import org.springframework.security.web.DefaultRedirectStrategy; 17 | import org.springframework.security.web.RedirectStrategy; 18 | import org.springframework.security.web.session.InvalidSessionStrategy; 19 | import org.springframework.security.web.util.UrlUtils; 20 | import org.springframework.util.Assert; 21 | 22 | import com.fasterxml.jackson.databind.ObjectMapper; 23 | import com.imooc.security.core.support.SimpleResponse; 24 | 25 | /** 26 | * @author lizhuquan 27 | * 28 | */ 29 | public class ImoocInvalidSessionStrategy implements InvalidSessionStrategy { 30 | 31 | private final Logger logger = LoggerFactory.getLogger(getClass()); 32 | /** 33 | * 跳转的url 34 | */ 35 | private String destinationUrl; 36 | /** 37 | * 重定向策略 38 | */ 39 | private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); 40 | /** 41 | * 跳转前是否创建新的session 42 | */ 43 | private boolean createNewSession = true; 44 | 45 | private ObjectMapper objectMapper = new ObjectMapper(); 46 | 47 | public ImoocInvalidSessionStrategy(String invalidSessionUrl) { 48 | Assert.isTrue(UrlUtils.isValidRedirectUrl(invalidSessionUrl), "url must start with '/' or with 'http(s)'"); 49 | this.destinationUrl = invalidSessionUrl; 50 | } 51 | 52 | @Override 53 | public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse response) 54 | throws IOException, ServletException { 55 | if (createNewSession) { 56 | request.getSession(); 57 | } 58 | 59 | String sourceUrl = request.getRequestURI(); 60 | 61 | if (StringUtils.endsWithIgnoreCase(sourceUrl, ".html")) { 62 | logger.info("session失效,跳转到" + destinationUrl); 63 | redirectStrategy.sendRedirect(request, response, destinationUrl); 64 | }else{ 65 | String message = "session已失效"; 66 | if(isConcurrency()){ 67 | message = message + ",有可能是并发登录导致的,可自定义InvalidSessionStrategy的Bean来覆盖默认逻辑"; 68 | } 69 | response.setStatus(HttpStatus.UNAUTHORIZED.value()); 70 | response.setContentType("application/json;charset=UTF-8"); 71 | response.getWriter().write(objectMapper.writeValueAsString(new SimpleResponse(message))); 72 | } 73 | } 74 | 75 | /** 76 | * session失效是否是并发导致的 77 | * @return 78 | */ 79 | protected boolean isConcurrency() { 80 | return false; 81 | } 82 | 83 | /** 84 | * Determines whether a new session should be created before redirecting (to 85 | * avoid possible looping issues where the same session ID is sent with the 86 | * redirected request). Alternatively, ensure that the configured URL does 87 | * not pass through the {@code SessionManagementFilter}. 88 | * 89 | * @param createNewSession 90 | * defaults to {@code true}. 91 | */ 92 | public void setCreateNewSession(boolean createNewSession) { 93 | this.createNewSession = createNewSession; 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /imooc-security-browser/src/main/resources/resources/imooc-banding.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | imooc 绑定 6 | 7 | 8 | 9 |

这是标准的绑定页面, 这里以qq为例

10 |
11 | 12 |
13 |
14 |

解绑QQ的话需要发送/connect/{providerId}的delete请求

15 | 16 | -------------------------------------------------------------------------------- /imooc-security-browser/src/main/resources/resources/imooc-session-invalid.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 会话失效 6 | 7 | 8 |

会话失效, 请到登陆页重新登陆

9 |

可通过imooc.security.browser.session.session-invalid-redirect-url配置自定义会话失效跳转url

10 | 11 | -------------------------------------------------------------------------------- /imooc-security-browser/src/main/resources/resources/imooc-signin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | imooc 登录 6 | 7 | 8 | 9 | 10 |

用户名登录

11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 27 | 28 | 29 | 记住我 30 | 31 | 32 | 33 | 34 |
用户名:
密码:
图形验证码: 24 | 25 | 26 |
35 |
36 | 37 |
38 | 39 |

手机登录

40 |
41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 52 | 53 | 54 | 55 | 56 |
手机号:
图形验证码: 49 | 50 | 发送验证码 51 |
57 |
58 | 59 |

社交登陆

60 | QQ登陆 61 | 62 | 73 | 74 | -------------------------------------------------------------------------------- /imooc-security-browser/src/main/resources/resources/imooc-signout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 退出登陆 6 | 7 | 8 |

imooc 退出登陆成功

9 | 10 | -------------------------------------------------------------------------------- /imooc-security-browser/src/main/resources/resources/imooc-signup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | imooc 注册 6 | 7 | 8 | 9 |

这是系统注册页面, 请配置immoc.security.browser.signUpUrl属性来设置自己的注册页

10 | 11 | -------------------------------------------------------------------------------- /imooc-security-browser/笔记-browser.txt: -------------------------------------------------------------------------------- 1 | 1. SpringSecurity过滤器链原理 2 | 一个认证过滤器链(UsernamePassword/Basic/...)-> ExceptionTranslationFilter -> FilterSecurityInterceptor 3 | 4 | 2. 登陆相关的逻辑 5 | UserDetailsService 处理用户登陆信息的获取逻辑 6 | UserDetails 处理用户校验的逻辑 7 | PasswordEncoder 处理密码的加密解密 8 | 9 | 3. PasswordEncoder可对用户的密码进行加密和校验 -------------------------------------------------------------------------------- /imooc-security-core/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | 3 | /.apt_generated/ 4 | 5 | 6 | .factorypath -------------------------------------------------------------------------------- /imooc-security-core/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | imooc-security-core 5 | 6 | com.imooc.security 7 | imooc-security 8 | 0.0.1-SNAPSHOT 9 | 10 | ${imooc.security.version} 11 | 12 | 13 | 14 | org.springframework.cloud 15 | spring-cloud-starter-oauth2 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-data-redis 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-jdbc 24 | 25 | 26 | mysql 27 | mysql-connector-java 28 | 29 | 30 | commons-lang 31 | commons-lang 32 | 33 | 34 | commons-collections 35 | commons-collections 36 | 37 | 38 | commons-beanutils 39 | commons-beanutils 40 | 41 | 42 | org.springframework.social 43 | spring-social-config 44 | 45 | 46 | org.springframework.social 47 | spring-social-core 48 | 49 | 50 | org.springframework.social 51 | spring-social-security 52 | 53 | 54 | org.springframework.social 55 | spring-social-web 56 | 57 | 58 | org.springframework.boot 59 | spring-boot-configuration-processor 60 | 61 | 62 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/CoreSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | import com.imooc.security.core.properties.SecurityProperties; 9 | import com.imooc.security.core.validate.code.image.DefaultImageCodeGenerator; 10 | import com.imooc.security.core.validate.code.image.ImageCodeGenerator; 11 | import com.imooc.security.core.validate.code.sms.DefaultSmsCodeGenerator; 12 | import com.imooc.security.core.validate.code.sms.DefaultSmsCodeSender; 13 | import com.imooc.security.core.validate.code.sms.SmsCodeGenerator; 14 | import com.imooc.security.core.validate.code.sms.SmsCodeSender; 15 | 16 | 17 | @Configuration 18 | public class CoreSecurityConfig { 19 | 20 | @Autowired 21 | private SecurityProperties securityProperties; 22 | 23 | @Bean 24 | @ConditionalOnMissingBean(value = ImageCodeGenerator.class) 25 | public ImageCodeGenerator imageCodeGenerator() { 26 | DefaultImageCodeGenerator imageCodeGenerator = new DefaultImageCodeGenerator(); 27 | imageCodeGenerator.setSecurityProperties(securityProperties); 28 | return imageCodeGenerator; 29 | } 30 | 31 | @Bean 32 | @ConditionalOnMissingBean(value = SmsCodeGenerator.class) 33 | public SmsCodeGenerator smsCodeGenerator() { 34 | DefaultSmsCodeGenerator smsCodeGenerator = new DefaultSmsCodeGenerator(); 35 | smsCodeGenerator.setSecurityProperties(securityProperties); 36 | return smsCodeGenerator; 37 | } 38 | 39 | @Bean 40 | @ConditionalOnMissingBean(value = SmsCodeSender.class) 41 | public SmsCodeSender smsCodeSender() { 42 | DefaultSmsCodeSender smsCodeSender = new DefaultSmsCodeSender(); 43 | return smsCodeSender; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/CoreSecurityCustomiableBeanConfig.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core; 2 | 3 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 9 | import org.springframework.security.crypto.password.PasswordEncoder; 10 | 11 | import redis.clients.jedis.JedisPoolConfig; 12 | 13 | @Configuration 14 | public class CoreSecurityCustomiableBeanConfig { 15 | 16 | @Bean 17 | @ConditionalOnMissingBean(value = PasswordEncoder.class) 18 | public PasswordEncoder passwordEncoder() { 19 | return new BCryptPasswordEncoder(); 20 | } 21 | 22 | @Bean 23 | @ConditionalOnMissingBean(value = RedisTemplate.class) 24 | public RedisTemplate getRedisTemplate(){ 25 | JedisConnectionFactory factory = new JedisConnectionFactory(); 26 | factory.setPoolConfig(new JedisPoolConfig()); 27 | factory.afterPropertiesSet(); 28 | 29 | RedisTemplate template = new RedisTemplate<>(); 30 | template.setConnectionFactory(factory); 31 | template.afterPropertiesSet(); 32 | 33 | return template; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/authentication/mobile/SmsCodeAuthenticationFilter.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.authentication.mobile; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import javax.servlet.http.HttpServletResponse; 5 | 6 | import org.springframework.security.authentication.AuthenticationServiceException; 7 | import org.springframework.security.core.Authentication; 8 | import org.springframework.security.core.AuthenticationException; 9 | import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; 10 | import org.springframework.security.web.util.matcher.AntPathRequestMatcher; 11 | import org.springframework.util.Assert; 12 | 13 | import com.imooc.security.core.properties.contsant.SecurityConstants; 14 | 15 | public class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter { 16 | // ~ Static fields/initializers 17 | // ===================================================================================== 18 | public static final String IMOOC_FORM_MOBILE_KEY = SecurityConstants.DEFAULT_REQUEST_PARAMETER_MOBILE; 19 | 20 | private String mobileParameter = IMOOC_FORM_MOBILE_KEY; 21 | private boolean postOnly = true; 22 | 23 | // ~ Constructors 24 | // =================================================================================================== 25 | 26 | public SmsCodeAuthenticationFilter(String loginProcessUrlMobile) { 27 | super(new AntPathRequestMatcher(loginProcessUrlMobile, "POST")); 28 | } 29 | 30 | // ~ Methods 31 | // ======================================================================================================== 32 | 33 | public Authentication attemptAuthentication(HttpServletRequest request, 34 | HttpServletResponse response) throws AuthenticationException { 35 | if (postOnly && !request.getMethod().equals("POST")) { 36 | throw new AuthenticationServiceException( 37 | "Authentication method not supported: " + request.getMethod()); 38 | } 39 | 40 | String mobile = obtainMobile(request); 41 | 42 | if (mobile == null) { 43 | mobile = ""; 44 | } 45 | 46 | mobile = mobile.trim(); 47 | 48 | SmsCodeAuthenticationToken authRequest = new SmsCodeAuthenticationToken(mobile); 49 | 50 | // Allow subclasses to set the "details" property 51 | setDetails(request, authRequest); 52 | 53 | return this.getAuthenticationManager().authenticate(authRequest); 54 | } 55 | 56 | /** 57 | * Enables subclasses to override the composition of the username, such as by 58 | * including additional values and a separator. 59 | * 60 | * @param request so that request attributes can be retrieved 61 | * 62 | * @return the username that will be presented in the Authentication 63 | * request token to the AuthenticationManager 64 | */ 65 | protected String obtainMobile(HttpServletRequest request) { 66 | return request.getParameter(mobileParameter); 67 | } 68 | 69 | /** 70 | * Provided so that subclasses may configure what is put into the authentication 71 | * request's details property. 72 | * 73 | * @param request that an authentication request is being created for 74 | * @param authRequest the authentication request object that should have its details 75 | * set 76 | */ 77 | protected void setDetails(HttpServletRequest request, 78 | SmsCodeAuthenticationToken authRequest) { 79 | authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); 80 | } 81 | 82 | /** 83 | * Sets the parameter name which will be used to obtain the username from the login 84 | * request. 85 | * 86 | * @param usernameParameter the parameter name. Defaults to "username". 87 | */ 88 | public void setMobileParameter(String usernameParameter) { 89 | Assert.hasText(usernameParameter, "Username parameter must not be empty or null"); 90 | this.mobileParameter = usernameParameter; 91 | } 92 | 93 | /** 94 | * Defines whether only HTTP POST requests will be allowed by this filter. If set to 95 | * true, and an authentication request is received which is not a POST request, an 96 | * exception will be raised immediately and authentication will not be attempted. The 97 | * unsuccessfulAuthentication() method will be called as if handling a failed 98 | * authentication. 99 | *

100 | * Defaults to true but may be overridden by subclasses. 101 | */ 102 | public void setPostOnly(boolean postOnly) { 103 | this.postOnly = postOnly; 104 | } 105 | 106 | public final String getMobileParameter() { 107 | return mobileParameter; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/authentication/mobile/SmsCodeAuthenticationProvider.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.authentication.mobile; 2 | 3 | import org.springframework.security.authentication.AuthenticationProvider; 4 | import org.springframework.security.authentication.InternalAuthenticationServiceException; 5 | import org.springframework.security.core.Authentication; 6 | import org.springframework.security.core.AuthenticationException; 7 | import org.springframework.security.core.userdetails.UserDetails; 8 | import org.springframework.security.core.userdetails.UserDetailsService; 9 | 10 | public class SmsCodeAuthenticationProvider implements AuthenticationProvider { 11 | 12 | private UserDetailsService userDetailsService; 13 | 14 | @Override 15 | public Authentication authenticate(Authentication authentication) throws AuthenticationException { 16 | SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication; 17 | 18 | UserDetails user = userDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal()); 19 | 20 | if (user == null) { 21 | throw new InternalAuthenticationServiceException("无法获取用户信息"); 22 | } 23 | 24 | SmsCodeAuthenticationToken authenticationResult = new SmsCodeAuthenticationToken(user, user.getAuthorities()); 25 | 26 | authenticationResult.setDetails(authenticationToken.getDetails()); 27 | return authenticationResult; 28 | } 29 | 30 | @Override 31 | public boolean supports(Class authentication) { 32 | return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication); 33 | } 34 | 35 | public UserDetailsService getUserDetailsService() { 36 | return userDetailsService; 37 | } 38 | 39 | public void setUserDetailsService(UserDetailsService userDetailsService) { 40 | this.userDetailsService = userDetailsService; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/authentication/mobile/SmsCodeAuthenticationSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.authentication.mobile; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.security.authentication.AuthenticationManager; 5 | import org.springframework.security.config.annotation.SecurityConfigurerAdapter; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.core.userdetails.UserDetailsService; 8 | import org.springframework.security.web.DefaultSecurityFilterChain; 9 | import org.springframework.security.web.authentication.AuthenticationFailureHandler; 10 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler; 11 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; 12 | import org.springframework.stereotype.Component; 13 | 14 | import com.imooc.security.core.properties.SecurityProperties; 15 | 16 | @Component 17 | public class SmsCodeAuthenticationSecurityConfig extends SecurityConfigurerAdapter{ 18 | 19 | @Autowired 20 | private AuthenticationSuccessHandler authenticationSuccessHandler; 21 | 22 | @Autowired 23 | private AuthenticationFailureHandler authenticationFailureHandler; 24 | 25 | @Autowired 26 | private UserDetailsService userDetailsService; 27 | 28 | @Autowired 29 | private SecurityProperties securityProperties; 30 | 31 | @Override 32 | public void configure(HttpSecurity http) throws Exception { 33 | SmsCodeAuthenticationFilter smsCodeAuthenticationFilter = new SmsCodeAuthenticationFilter(securityProperties.getBrowser().getSigninProcessUrlMobile()); 34 | smsCodeAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class)); 35 | smsCodeAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler); 36 | smsCodeAuthenticationFilter.setAuthenticationFailureHandler(authenticationFailureHandler); 37 | 38 | SmsCodeAuthenticationProvider provider = new SmsCodeAuthenticationProvider(); 39 | provider.setUserDetailsService(userDetailsService); 40 | 41 | http 42 | .authenticationProvider(provider) 43 | .addFilterAfter(smsCodeAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/authentication/mobile/SmsCodeAuthenticationToken.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.authentication.mobile; 2 | 3 | import java.util.Collection; 4 | 5 | import org.springframework.security.authentication.AbstractAuthenticationToken; 6 | import org.springframework.security.core.GrantedAuthority; 7 | 8 | public class SmsCodeAuthenticationToken extends AbstractAuthenticationToken { 9 | /** 10 | * 11 | */ 12 | private static final long serialVersionUID = 1L; 13 | 14 | // ~ Instance fields 15 | // ================================================================================================ 16 | private final Object principal; 17 | 18 | // ~ Constructors 19 | // =================================================================================================== 20 | 21 | /** 22 | * This constructor can be safely used by any code that wishes to create a 23 | * UsernamePasswordAuthenticationToken, as the {@link #isAuthenticated()} 24 | * will return false. 25 | * 26 | */ 27 | public SmsCodeAuthenticationToken(Object mobile) { 28 | super(null); 29 | this.principal = mobile; 30 | setAuthenticated(false); 31 | } 32 | 33 | /** 34 | * This constructor should only be used by AuthenticationManager or 35 | * AuthenticationProvider implementations that are satisfied with 36 | * producing a trusted (i.e. {@link #isAuthenticated()} = true) 37 | * authentication token. 38 | * 39 | * @param principal 40 | * @param credentials 41 | * @param authorities 42 | */ 43 | public SmsCodeAuthenticationToken(Object principal, Collection authorities) { 44 | super(authorities); 45 | this.principal = principal; 46 | super.setAuthenticated(true); // must use super, as we override 47 | } 48 | 49 | // ~ Methods 50 | // ======================================================================================================== 51 | public Object getPrincipal() { 52 | return this.principal; 53 | } 54 | 55 | public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { 56 | if (isAuthenticated) { 57 | throw new IllegalArgumentException( 58 | "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); 59 | } 60 | 61 | super.setAuthenticated(false); 62 | } 63 | 64 | @Override 65 | public void eraseCredentials() { 66 | super.eraseCredentials(); 67 | } 68 | 69 | @Override 70 | public Object getCredentials() { 71 | return null; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/authentication/openid/OpenIdAuthenticationProvider.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.authentication.openid; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | import org.springframework.security.authentication.AuthenticationProvider; 7 | import org.springframework.security.authentication.InternalAuthenticationServiceException; 8 | import org.springframework.security.core.Authentication; 9 | import org.springframework.security.core.AuthenticationException; 10 | import org.springframework.security.core.userdetails.UserDetails; 11 | import org.springframework.social.connect.UsersConnectionRepository; 12 | import org.springframework.social.security.SocialUserDetailsService; 13 | import org.springframework.util.CollectionUtils; 14 | 15 | public class OpenIdAuthenticationProvider implements AuthenticationProvider { 16 | 17 | private SocialUserDetailsService userDetailsService; 18 | 19 | private UsersConnectionRepository usersConnectionRepository; 20 | 21 | @Override 22 | public Authentication authenticate(Authentication authentication) throws AuthenticationException { 23 | 24 | OpenIdAuthenticationToken authenticationToken = (OpenIdAuthenticationToken) authentication; 25 | 26 | Set providerUserIds = new HashSet<>(); 27 | providerUserIds.add((String)authenticationToken.getPrincipal()); 28 | Set userIds = usersConnectionRepository.findUserIdsConnectedTo(authenticationToken.getProviderId(), providerUserIds); 29 | 30 | if (CollectionUtils.isEmpty(userIds) || userIds.size() != 1) { 31 | throw new InternalAuthenticationServiceException("无法获取用户信息"); 32 | } 33 | 34 | String userId = userIds.iterator().next(); 35 | 36 | UserDetails user = userDetailsService.loadUserByUserId(userId); 37 | 38 | if (user == null) { 39 | throw new InternalAuthenticationServiceException("无法获取用户信息"); 40 | } 41 | 42 | OpenIdAuthenticationToken authenticationResult = new OpenIdAuthenticationToken(user, user.getAuthorities()); 43 | 44 | authenticationResult.setDetails(authenticationToken.getDetails()); 45 | return authenticationResult; 46 | } 47 | 48 | @Override 49 | public boolean supports(Class authentication) { 50 | return OpenIdAuthenticationToken.class.isAssignableFrom(authentication); 51 | } 52 | 53 | public SocialUserDetailsService getUserDetailsService() { 54 | return userDetailsService; 55 | } 56 | 57 | public void setUserDetailsService(SocialUserDetailsService userDetailsService) { 58 | this.userDetailsService = userDetailsService; 59 | } 60 | 61 | public UsersConnectionRepository getUsersConnectionRepository() { 62 | return usersConnectionRepository; 63 | } 64 | 65 | public void setUsersConnectionRepository(UsersConnectionRepository usersConnectionRepository) { 66 | this.usersConnectionRepository = usersConnectionRepository; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/authentication/openid/OpenIdAuthenticationSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.authentication.openid; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.security.authentication.AuthenticationManager; 5 | import org.springframework.security.config.annotation.SecurityConfigurerAdapter; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.web.DefaultSecurityFilterChain; 8 | import org.springframework.security.web.authentication.AuthenticationFailureHandler; 9 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler; 10 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; 11 | import org.springframework.social.connect.UsersConnectionRepository; 12 | import org.springframework.social.security.SocialUserDetailsService; 13 | import org.springframework.stereotype.Component; 14 | 15 | import com.imooc.security.core.properties.SecurityProperties; 16 | 17 | @Component 18 | public class OpenIdAuthenticationSecurityConfig extends SecurityConfigurerAdapter{ 19 | 20 | @Autowired 21 | private AuthenticationSuccessHandler authenticationSuccessHandler; 22 | 23 | @Autowired 24 | private AuthenticationFailureHandler authenticationFailureHandler; 25 | 26 | @Autowired 27 | private SocialUserDetailsService userDetailsService; 28 | 29 | @Autowired 30 | private SecurityProperties securityProperties; 31 | 32 | @Autowired 33 | private UsersConnectionRepository usersConnectionRepository; 34 | 35 | @Override 36 | public void configure(HttpSecurity http) throws Exception { 37 | OpenIdAuthenticationFilter openIdAuthenticationFilter = new OpenIdAuthenticationFilter(securityProperties.getApp().getSigninProcessUrlOpenId()); 38 | openIdAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class)); 39 | openIdAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler); 40 | openIdAuthenticationFilter.setAuthenticationFailureHandler(authenticationFailureHandler); 41 | 42 | OpenIdAuthenticationProvider provider = new OpenIdAuthenticationProvider(); 43 | provider.setUserDetailsService(userDetailsService); 44 | provider.setUsersConnectionRepository(usersConnectionRepository); 45 | 46 | http 47 | .authenticationProvider(provider) 48 | .addFilterAfter(openIdAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/authentication/openid/OpenIdAuthenticationToken.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.authentication.openid; 2 | 3 | import java.util.Collection; 4 | 5 | import org.springframework.security.authentication.AbstractAuthenticationToken; 6 | import org.springframework.security.core.GrantedAuthority; 7 | 8 | public class OpenIdAuthenticationToken extends AbstractAuthenticationToken { 9 | /** 10 | * 11 | */ 12 | private static final long serialVersionUID = 1L; 13 | 14 | // ~ Instance fields 15 | // ================================================================================================ 16 | private final Object principal; 17 | private String providerId; 18 | 19 | // ~ Constructors 20 | // =================================================================================================== 21 | 22 | /** 23 | * This constructor can be safely used by any code that wishes to create a 24 | * UsernamePasswordAuthenticationToken, as the {@link #isAuthenticated()} 25 | * will return false. 26 | * 27 | */ 28 | public OpenIdAuthenticationToken(Object openId, String providerId) { 29 | super(null); 30 | this.principal = openId; 31 | this.providerId = providerId; 32 | setAuthenticated(false); 33 | } 34 | 35 | /** 36 | * This constructor should only be used by AuthenticationManager or 37 | * AuthenticationProvider implementations that are satisfied with 38 | * producing a trusted (i.e. {@link #isAuthenticated()} = true) 39 | * authentication token. 40 | * 41 | * @param principal 42 | * @param credentials 43 | * @param authorities 44 | */ 45 | public OpenIdAuthenticationToken(Object openId, Collection authorities) { 46 | super(authorities); 47 | this.principal = openId; 48 | super.setAuthenticated(true); // must use super, as we override 49 | } 50 | 51 | // ~ Methods 52 | // ======================================================================================================== 53 | public Object getPrincipal() { 54 | return this.principal; 55 | } 56 | 57 | public String getProviderId() { 58 | return this.providerId; 59 | } 60 | 61 | public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { 62 | if (isAuthenticated) { 63 | throw new IllegalArgumentException( 64 | "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); 65 | } 66 | 67 | super.setAuthenticated(false); 68 | } 69 | 70 | @Override 71 | public void eraseCredentials() { 72 | super.eraseCredentials(); 73 | } 74 | 75 | @Override 76 | public Object getCredentials() { 77 | return null; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/authorize/AuthorizeConfigManager.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.authorize; 2 | 3 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 4 | import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; 5 | 6 | public interface AuthorizeConfigManager { 7 | 8 | void config(ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry config); 9 | } 10 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/authorize/AuthorizeConfigProvider.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.authorize; 2 | 3 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 4 | import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; 5 | 6 | public interface AuthorizeConfigProvider { 7 | 8 | void config(ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry config); 9 | } 10 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/authorize/ImoocAuthorizeConfigManager.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.authorize; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component 11 | public class ImoocAuthorizeConfigManager implements AuthorizeConfigManager { 12 | 13 | @Autowired 14 | private List authorizeConfigProviders; 15 | 16 | @Override 17 | public void config(ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry config) { 18 | for (AuthorizeConfigProvider authorizeConfigProvider : authorizeConfigProviders) { 19 | authorizeConfigProvider.config(config); 20 | } 21 | // 其它所有请求需要身份验证 22 | // config.anyRequest().authenticated(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/authorize/ImoocAuthorizeConfigProvider.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.authorize; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.core.annotation.Order; 5 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 6 | import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; 7 | import org.springframework.stereotype.Component; 8 | 9 | import com.imooc.security.core.properties.SecurityProperties; 10 | 11 | @Component 12 | @Order(Integer.MIN_VALUE) 13 | public class ImoocAuthorizeConfigProvider implements AuthorizeConfigProvider { 14 | 15 | @Autowired 16 | private SecurityProperties securityProperties; 17 | 18 | @Override 19 | public void config(ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry config) { 20 | config.antMatchers( 21 | securityProperties.getBrowser().getSignupPageUrl(), 22 | securityProperties.getBrowser().getSignupProcessUrl(), 23 | securityProperties.getBrowser().getUnAuthenticationUrl(), 24 | securityProperties.getBrowser().getSigninPageUrl(), 25 | securityProperties.getBrowser().getSigninProcessUrlMobile(), 26 | securityProperties.getBrowser().getValidateCodeUrlImage(), 27 | securityProperties.getBrowser().getValidateCodeUrlSms(), 28 | securityProperties.getBrowser().getSession().getSessionInvalidRedirectUrl(), 29 | securityProperties.getBrowser().getSignoutSuccessUrl() 30 | ) 31 | //放行 32 | .permitAll(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/exception/AppSecurityException.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.exception; 2 | 3 | public class AppSecurityException extends RuntimeException { 4 | 5 | /** 6 | * 7 | */ 8 | private static final long serialVersionUID = 1L; 9 | 10 | public AppSecurityException(String msg) { 11 | super(msg); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/properties/AppProperties.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.properties; 2 | 3 | import com.imooc.security.core.properties.contsant.SecurityConstants; 4 | 5 | public class AppProperties { 6 | 7 | private String signinProcessUrlOpenId = SecurityConstants.DEFAULT_SIGNIN_PROCESS_URL_OPENID; 8 | 9 | 10 | public String getSigninProcessUrlOpenId() { 11 | return signinProcessUrlOpenId; 12 | } 13 | 14 | public void setSigninProcessUrlOpenId(String signinProcessUrlOpenId) { 15 | this.signinProcessUrlOpenId = signinProcessUrlOpenId; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/properties/BrowserProperties.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.properties; 2 | 3 | import com.imooc.security.core.properties.contsant.AuthenticationResponseTypeEnum; 4 | import com.imooc.security.core.properties.contsant.SecurityConstants; 5 | 6 | public class BrowserProperties { 7 | private String signupPageUrl = SecurityConstants.DEFAULT_SINGUP_PAGE_URL; 8 | private String signupProcessUrl = SecurityConstants.DEFAULT_SINGUP_PROCESS_URL; 9 | private String unAuthenticationUrl = SecurityConstants.DEFAULT_UNAUTHENTICATION_URL; 10 | private String signinPageUrl = SecurityConstants.DEFAULT_SIGNIN_PAGE_URL; 11 | private String validateCodeUrlImage = SecurityConstants.DEFAULT_VALIDATE_CODE_URL_IMAGE; 12 | private String validateCodeUrlSms = SecurityConstants.DEFAULT_VALIDATE_CODE_URL_SMS; 13 | private String signinProcessUrlForm = SecurityConstants.DEFAULT_SIGNIN_PROCESS_URL_FORM; 14 | private String signinProcessUrlMobile = SecurityConstants.DEFAULT_SIGNIN_PROCESS_URL_MOBILE; 15 | private AuthenticationResponseTypeEnum authentionResponseType = AuthenticationResponseTypeEnum.JSON; 16 | private int rememberMeSeconds = 604800; 17 | private String signoutUrl = SecurityConstants.DEFAULT_SIGNOUT_URL; 18 | private String signoutSuccessUrl = SecurityConstants.DEFAULT_SIGNOUT_SUCCESS_URL; 19 | private String[] signoutDeleteCookies = SecurityConstants.DEFAULT_SIGNOUT_DELETE_COOKIES; 20 | 21 | private SessionProperties session = new SessionProperties(); 22 | 23 | public AuthenticationResponseTypeEnum getAuthentionResponseType() { 24 | return authentionResponseType; 25 | } 26 | 27 | public void setAuthentionResponseType(AuthenticationResponseTypeEnum authentionResponseType) { 28 | this.authentionResponseType = authentionResponseType; 29 | } 30 | 31 | public int getRememberMeSeconds() { 32 | return rememberMeSeconds; 33 | } 34 | 35 | public void setRememberMeSeconds(int rememberMeSeconds) { 36 | this.rememberMeSeconds = rememberMeSeconds; 37 | } 38 | 39 | public String getUnAuthenticationUrl() { 40 | return unAuthenticationUrl; 41 | } 42 | 43 | public void setUnAuthenticationUrl(String unAuthenticationUrl) { 44 | this.unAuthenticationUrl = unAuthenticationUrl; 45 | } 46 | 47 | public String getSigninPageUrl() { 48 | return signinPageUrl; 49 | } 50 | 51 | public void setSigninPageUrl(String signinPageUrl) { 52 | this.signinPageUrl = signinPageUrl; 53 | } 54 | 55 | public String getSigninProcessUrlForm() { 56 | return signinProcessUrlForm; 57 | } 58 | 59 | public void setSigninProcessUrlForm(String signinProcessUrlForm) { 60 | this.signinProcessUrlForm = signinProcessUrlForm; 61 | } 62 | 63 | public String getSigninProcessUrlMobile() { 64 | return signinProcessUrlMobile; 65 | } 66 | 67 | public void setSigninProcessUrlMobile(String signinProcessUrlMobile) { 68 | this.signinProcessUrlMobile = signinProcessUrlMobile; 69 | } 70 | 71 | public String getValidateCodeUrlImage() { 72 | return validateCodeUrlImage; 73 | } 74 | 75 | public void setValidateCodeUrlImage(String validateCodeUrlImage) { 76 | this.validateCodeUrlImage = validateCodeUrlImage; 77 | } 78 | 79 | public String getValidateCodeUrlSms() { 80 | return validateCodeUrlSms; 81 | } 82 | 83 | public void setValidateCodeUrlSms(String validateCodeUrlSms) { 84 | this.validateCodeUrlSms = validateCodeUrlSms; 85 | } 86 | 87 | public String getSignupPageUrl() { 88 | return signupPageUrl; 89 | } 90 | 91 | public void setSignupPageUrl(String signupPageUrl) { 92 | this.signupPageUrl = signupPageUrl; 93 | } 94 | 95 | public String getSignupProcessUrl() { 96 | return signupProcessUrl; 97 | } 98 | 99 | public void setSignupProcessUrl(String signupProcessUrl) { 100 | this.signupProcessUrl = signupProcessUrl; 101 | } 102 | 103 | public SessionProperties getSession() { 104 | return session; 105 | } 106 | 107 | public void setSession(SessionProperties session) { 108 | this.session = session; 109 | } 110 | 111 | public String getSignoutUrl() { 112 | return signoutUrl; 113 | } 114 | 115 | public void setSignoutUrl(String signoutUrl) { 116 | this.signoutUrl = signoutUrl; 117 | } 118 | 119 | public String getSignoutSuccessUrl() { 120 | return signoutSuccessUrl; 121 | } 122 | 123 | public void setSignoutSuccessUrl(String signoutSuccessUrl) { 124 | this.signoutSuccessUrl = signoutSuccessUrl; 125 | } 126 | 127 | public String[] getSignoutDeleteCookies() { 128 | return signoutDeleteCookies; 129 | } 130 | 131 | public void setSignoutDeleteCookies(String[] signoutDeleteCookies) { 132 | this.signoutDeleteCookies = signoutDeleteCookies; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/properties/ImageCodeProperties.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.properties; 2 | 3 | public class ImageCodeProperties extends SmsCodeProperties { 4 | private int width = 80; 5 | private int height = 45; 6 | private int fontSize = 40; 7 | 8 | public ImageCodeProperties() { 9 | setLength(4); 10 | } 11 | 12 | public int getWidth() { 13 | return width; 14 | } 15 | public void setWidth(int width) { 16 | this.width = width; 17 | } 18 | public int getHeight() { 19 | return height; 20 | } 21 | public void setHeight(int height) { 22 | this.height = height; 23 | } 24 | public int getFontSize() { 25 | return fontSize; 26 | } 27 | public void setFontSize(int fontSize) { 28 | this.fontSize = fontSize; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/properties/OAuth2ClientProperties.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.properties; 2 | 3 | public class OAuth2ClientProperties { 4 | private String clientId; 5 | private String clientSecret; 6 | private int accessTokenValiditySeconds; 7 | public String getClientId() { 8 | return clientId; 9 | } 10 | public void setClientId(String clientId) { 11 | this.clientId = clientId; 12 | } 13 | public String getClientSecret() { 14 | return clientSecret; 15 | } 16 | public void setClientSecret(String clientSecret) { 17 | this.clientSecret = clientSecret; 18 | } 19 | public int getAccessTokenValiditySeconds() { 20 | return accessTokenValiditySeconds; 21 | } 22 | public void setAccessTokenValiditySeconds(int accessTokenValiditySeconds) { 23 | this.accessTokenValiditySeconds = accessTokenValiditySeconds; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/properties/OAuth2Properties.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.properties; 2 | 3 | public class OAuth2Properties { 4 | 5 | private String signingKey = "imooc"; 6 | 7 | private OAuth2ClientProperties[] clients = {}; 8 | 9 | public OAuth2ClientProperties[] getClients() { 10 | return clients; 11 | } 12 | 13 | public void setClients(OAuth2ClientProperties[] clients) { 14 | this.clients = clients; 15 | } 16 | 17 | public String getSigningKey() { 18 | return signingKey; 19 | } 20 | 21 | public void setSigningKey(String signingKey) { 22 | this.signingKey = signingKey; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/properties/QQProperties.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.properties; 2 | 3 | import org.springframework.boot.autoconfigure.social.SocialProperties; 4 | 5 | public class QQProperties extends SocialProperties { 6 | 7 | private String providerId = "qq"; 8 | 9 | public String getProviderId() { 10 | return providerId; 11 | } 12 | 13 | public void setProviderId(String providerId) { 14 | this.providerId = providerId; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/properties/SecurityProperties.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.properties; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | import org.springframework.stereotype.Component; 5 | 6 | @ConfigurationProperties(prefix = "imooc.security") 7 | @Component(value = "globalSecurityProperties") 8 | public class SecurityProperties { 9 | 10 | private BrowserProperties browser = new BrowserProperties(); 11 | 12 | private ValidateCodeProperties code = new ValidateCodeProperties(); 13 | 14 | private SocialProperties social = new SocialProperties(); 15 | 16 | private AppProperties app = new AppProperties(); 17 | 18 | private OAuth2Properties oauth2 = new OAuth2Properties(); 19 | 20 | public BrowserProperties getBrowser() { 21 | return browser; 22 | } 23 | 24 | public void setBrowser(BrowserProperties browser) { 25 | this.browser = browser; 26 | } 27 | 28 | public ValidateCodeProperties getCode() { 29 | return code; 30 | } 31 | 32 | public void setCode(ValidateCodeProperties code) { 33 | this.code = code; 34 | } 35 | 36 | public SocialProperties getSocial() { 37 | return social; 38 | } 39 | 40 | public void setSocial(SocialProperties social) { 41 | this.social = social; 42 | } 43 | 44 | public AppProperties getApp() { 45 | return app; 46 | } 47 | 48 | public void setApp(AppProperties app) { 49 | this.app = app; 50 | } 51 | 52 | public OAuth2Properties getOauth2() { 53 | return oauth2; 54 | } 55 | 56 | public void setOauth2(OAuth2Properties oauth2) { 57 | this.oauth2 = oauth2; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/properties/SessionProperties.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.properties; 2 | 3 | import com.imooc.security.core.properties.contsant.SecurityConstants; 4 | 5 | public class SessionProperties { 6 | 7 | private String sessionInvalidRedirectUrl = SecurityConstants.DEFAULT_INVALID_SESSION_REDIRECT_URL; 8 | 9 | private int maxinumSession = SecurityConstants.DEFAULT_MAX_SESSIOIN_PRE_USER; 10 | 11 | private boolean maxSessionsPreventsLogin = SecurityConstants.DEFAULT_MAX_SESSION_PREVENTS_LOGIN; 12 | 13 | public String getSessionInvalidRedirectUrl() { 14 | return sessionInvalidRedirectUrl; 15 | } 16 | 17 | public void setSessionInvalidRedirectUrl(String sessionInvalidRedirectUrl) { 18 | this.sessionInvalidRedirectUrl = sessionInvalidRedirectUrl; 19 | } 20 | 21 | public int getMaxinumSession() { 22 | return maxinumSession; 23 | } 24 | 25 | public void setMaxinumSession(int maxinumSession) { 26 | this.maxinumSession = maxinumSession; 27 | } 28 | 29 | public boolean isMaxSessionsPreventsLogin() { 30 | return maxSessionsPreventsLogin; 31 | } 32 | 33 | public void setMaxSessionsPreventsLogin(boolean maxSessionsPreventsLogin) { 34 | this.maxSessionsPreventsLogin = maxSessionsPreventsLogin; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/properties/SmsCodeProperties.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.properties; 2 | 3 | public class SmsCodeProperties { 4 | private int length = 6; 5 | private int expireIn = 300; 6 | private String url; 7 | 8 | public int getLength() { 9 | return length; 10 | } 11 | 12 | public void setLength(int length) { 13 | this.length = length; 14 | } 15 | 16 | public int getExpireIn() { 17 | return expireIn; 18 | } 19 | 20 | public void setExpireIn(int expireIn) { 21 | this.expireIn = expireIn; 22 | } 23 | 24 | public String getUrl() { 25 | return url; 26 | } 27 | 28 | public void setUrl(String url) { 29 | this.url = url; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/properties/SocialProperties.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.properties; 2 | 3 | public class SocialProperties { 4 | 5 | private String filterProcessUrl = "/auth"; 6 | 7 | private QQProperties qq = new QQProperties(); 8 | 9 | private WeixinProperties weixin = new WeixinProperties(); 10 | 11 | public QQProperties getQq() { 12 | return qq; 13 | } 14 | 15 | public void setQq(QQProperties qq) { 16 | this.qq = qq; 17 | } 18 | 19 | public WeixinProperties getWeixin() { 20 | return weixin; 21 | } 22 | 23 | public void setWeixin(WeixinProperties weixin) { 24 | this.weixin = weixin; 25 | } 26 | 27 | public String getFilterProcessUrl() { 28 | return filterProcessUrl; 29 | } 30 | 31 | public void setFilterProcessUrl(String filterProcessUrl) { 32 | this.filterProcessUrl = filterProcessUrl; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/properties/ValidateCodeProperties.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.properties; 2 | 3 | public class ValidateCodeProperties { 4 | 5 | private ImageCodeProperties image = new ImageCodeProperties(); 6 | 7 | private SmsCodeProperties sms = new SmsCodeProperties(); 8 | 9 | public ImageCodeProperties getImage() { 10 | return image; 11 | } 12 | 13 | public void setImage(ImageCodeProperties image) { 14 | this.image = image; 15 | } 16 | 17 | public SmsCodeProperties getSms() { 18 | return sms; 19 | } 20 | 21 | public void setSms(SmsCodeProperties sms) { 22 | this.sms = sms; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/properties/WeixinProperties.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.properties; 2 | 3 | import org.springframework.boot.autoconfigure.social.SocialProperties; 4 | 5 | public class WeixinProperties extends SocialProperties { 6 | 7 | private String providerId = "weixin"; 8 | 9 | public String getProviderId() { 10 | return providerId; 11 | } 12 | 13 | public void setProviderId(String providerId) { 14 | this.providerId = providerId; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/properties/contsant/AuthenticationResponseTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.properties.contsant; 2 | 3 | public enum AuthenticationResponseTypeEnum { 4 | DIRECT, 5 | JSON 6 | } 7 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/properties/contsant/SecurityConstants.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.properties.contsant; 2 | 3 | public class SecurityConstants { 4 | 5 | /** 6 | * 当请求需要身份认证时,默认跳转的url 7 | */ 8 | public static final String DEFAULT_UNAUTHENTICATION_URL = "/authentication/dispatch"; 9 | 10 | /** 11 | * 默认登录页面url 12 | */ 13 | public static final String DEFAULT_SIGNIN_PAGE_URL = "/imooc-signin.html"; 14 | 15 | /** 16 | * 默认注册也url 17 | */ 18 | public static final String DEFAULT_SINGUP_PAGE_URL = "/imooc-singup.html"; 19 | 20 | /** 21 | * 默认获取图像验证码的url 22 | */ 23 | public static final String DEFAULT_VALIDATE_CODE_URL_IMAGE = "/code/image"; 24 | 25 | /** 26 | * 默认获取短信验证码的url 27 | */ 28 | public static final String DEFAULT_VALIDATE_CODE_URL_SMS = "/code/sms"; 29 | 30 | /** 31 | * 注册处理url 32 | */ 33 | public static final String DEFAULT_SINGUP_PROCESS_URL = "/regist"; 34 | 35 | /** 36 | * 默认的用户名密码登录请求处理url 37 | */ 38 | public static final String DEFAULT_SIGNIN_PROCESS_URL_FORM = "/authentication/form"; 39 | 40 | /** 41 | * 默认的手机验证码登录请求处理url 42 | */ 43 | public static final String DEFAULT_SIGNIN_PROCESS_URL_MOBILE = "/authentication/mobile"; 44 | 45 | /** 46 | * 默认的openid登陆请求处理url 47 | */ 48 | public static final String DEFAULT_SIGNIN_PROCESS_URL_OPENID = "/authentication/openId"; 49 | 50 | /** 51 | * 验证图片验证码时,http请求中默认的携带图片验证码信息的参数的名称 52 | */ 53 | public static final String DEFAULT_REQUEST_PARAMETER_IMAGECODE = "imageCode"; 54 | 55 | /** 56 | * 验证短信验证码时,http请求中默认的携带短信验证码信息的参数的名称 57 | */ 58 | public static final String DEFAULT_REQUEST_PARAMETER_SMSCODE= "smsCode"; 59 | 60 | /** 61 | * 发送短信验证码 或 验证短信验证码时,传递手机号的参数的名称 62 | */ 63 | public static final String DEFAULT_REQUEST_PARAMETER_MOBILE = "mobile"; 64 | 65 | /** 66 | * 社交登陆时, 传递的openId参数名 67 | */ 68 | public static final String DEFAULT_REQUEST_PARAMETER_OPENID = "openId"; 69 | 70 | /** 71 | * 社交登陆时,传递的providerId参数名 72 | */ 73 | public static final String DEFAULT_REQUEST_PARAMETER_PROVIDERID = "providerId"; 74 | 75 | /** 76 | * 默认的Social UserConnection表名的前缀 77 | */ 78 | public static final String DEFAULT_SOCIAL_USER_CONNECTION_PREFIX = "imooc_"; 79 | 80 | /** 81 | * 默认的session失效时重定向地址 82 | */ 83 | public static final String DEFAULT_INVALID_SESSION_REDIRECT_URL = "/imooc-session-invalid.html"; 84 | 85 | /** 86 | * 默认同一用户最多产生的session数 87 | */ 88 | public static final int DEFAULT_MAX_SESSIOIN_PRE_USER = 1; 89 | 90 | /** 91 | * 默认如果超出最大session限制, 是否阻止用户登陆 92 | */ 93 | public static final boolean DEFAULT_MAX_SESSION_PREVENTS_LOGIN = false; 94 | 95 | /** 96 | * 默认退出登陆URL 97 | */ 98 | public static final String DEFAULT_SIGNOUT_URL = "/signout"; 99 | 100 | /** 101 | * 默认成功退出登陆URL 102 | */ 103 | public static final String DEFAULT_SIGNOUT_SUCCESS_URL = "/imooc-signout.html"; 104 | 105 | /** 106 | * 默认退出登陆后删除的cookies 107 | */ 108 | public static final String[] DEFAULT_SIGNOUT_DELETE_COOKIES = new String[] {"JSESSIONID", "SESSIONID"}; 109 | } 110 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/properties/contsant/ValidateCodeTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.properties.contsant; 2 | 3 | public enum ValidateCodeTypeEnum { 4 | IMAGE { 5 | @Override 6 | public String getParameterNameOnValidate() { 7 | return SecurityConstants.DEFAULT_REQUEST_PARAMETER_IMAGECODE; 8 | } 9 | }, 10 | SMS { 11 | @Override 12 | public String getParameterNameOnValidate() { 13 | return SecurityConstants.DEFAULT_REQUEST_PARAMETER_SMSCODE; 14 | } 15 | }; 16 | 17 | public abstract String getParameterNameOnValidate(); 18 | } 19 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/social/AppSignupUtils.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.social; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import org.apache.commons.lang.StringUtils; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | import org.springframework.social.connect.Connection; 9 | import org.springframework.social.connect.ConnectionData; 10 | import org.springframework.social.connect.ConnectionFactoryLocator; 11 | import org.springframework.social.connect.UsersConnectionRepository; 12 | import org.springframework.stereotype.Component; 13 | import org.springframework.web.context.request.WebRequest; 14 | 15 | import com.imooc.security.core.exception.AppSecurityException; 16 | 17 | 18 | @Component 19 | public class AppSignupUtils { 20 | 21 | @Autowired 22 | private RedisTemplate redisTemplate; 23 | 24 | @Autowired 25 | private UsersConnectionRepository usersConnectionRepository; 26 | 27 | @Autowired 28 | private ConnectionFactoryLocator connectionFactoryLocator; 29 | 30 | public void saveConnectionData(WebRequest request, ConnectionData connectionData) { 31 | redisTemplate.opsForValue().set(getKey(request), connectionData, 10, TimeUnit.MINUTES); 32 | } 33 | 34 | public void doPostSignUp(WebRequest request, String userId) { 35 | 36 | String key = getKey(request); 37 | if (!redisTemplate.hasKey(key)) { 38 | throw new AppSecurityException("无法找到缓存的第三方社交账号信息"); 39 | } 40 | 41 | ConnectionData connectionData = (ConnectionData) redisTemplate.opsForValue().get(key); 42 | 43 | Connection connection = connectionFactoryLocator.getConnectionFactory(connectionData.getProviderId()).createConnection(connectionData); 44 | 45 | usersConnectionRepository.createConnectionRepository(userId).addConnection(connection); 46 | 47 | redisTemplate.delete(key); 48 | } 49 | 50 | 51 | private String getKey(WebRequest request) { 52 | 53 | String deviceId = request.getHeader("deviceId"); 54 | if (StringUtils.isBlank(deviceId)) { 55 | throw new AppSecurityException("设备id不能为空"); 56 | } 57 | return "connectiondata:" + deviceId; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/social/ImoocSpringSocialConfigurer.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.social; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.social.security.SocialAuthenticationFilter; 5 | import org.springframework.social.security.SpringSocialConfigurer; 6 | 7 | public class ImoocSpringSocialConfigurer extends SpringSocialConfigurer { 8 | 9 | private String filterProcessUrl; 10 | 11 | @Autowired(required = false) 12 | private SocialAuthenticationFilterPostProcessor socialAuthenticationFilterPostProcessor; 13 | 14 | public ImoocSpringSocialConfigurer(String filterProcessUrl) { 15 | this.filterProcessUrl = filterProcessUrl; 16 | } 17 | 18 | /** 19 | * T是过滤器的filter 20 | */ 21 | @SuppressWarnings("unchecked") 22 | @Override 23 | protected T postProcess(T object) { 24 | SocialAuthenticationFilter filter = (SocialAuthenticationFilter) super.postProcess(object); 25 | filter.setFilterProcessesUrl(filterProcessUrl); 26 | if (socialAuthenticationFilterPostProcessor != null) { 27 | socialAuthenticationFilterPostProcessor.process(filter); 28 | } 29 | return (T) filter; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/social/SocialAuthenticationFilterPostProcessor.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.social; 2 | 3 | import org.springframework.social.security.SocialAuthenticationFilter; 4 | 5 | public interface SocialAuthenticationFilterPostProcessor { 6 | void process(SocialAuthenticationFilter socialAuthenticationFilter); 7 | } 8 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/social/SocialConfig.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.social; 2 | 3 | import javax.sql.DataSource; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.security.crypto.encrypt.Encryptors; 10 | import org.springframework.social.config.annotation.EnableSocial; 11 | import org.springframework.social.config.annotation.SocialConfigurerAdapter; 12 | import org.springframework.social.connect.ConnectionFactoryLocator; 13 | import org.springframework.social.connect.ConnectionSignUp; 14 | import org.springframework.social.connect.UsersConnectionRepository; 15 | import org.springframework.social.connect.jdbc.JdbcUsersConnectionRepository; 16 | import org.springframework.social.connect.web.ProviderSignInUtils; 17 | import org.springframework.social.security.SpringSocialConfigurer; 18 | import org.springframework.web.servlet.View; 19 | 20 | import com.imooc.security.core.properties.SecurityProperties; 21 | import com.imooc.security.core.properties.contsant.SecurityConstants; 22 | import com.imooc.security.core.social.view.ImoocConnecStatusView; 23 | 24 | @Configuration 25 | @EnableSocial 26 | public class SocialConfig extends SocialConfigurerAdapter { 27 | 28 | @Autowired 29 | private SecurityProperties securityProperties; 30 | 31 | @Autowired 32 | private DataSource dataSource; 33 | 34 | @Autowired(required = false) 35 | private ConnectionSignUp connectionSignUp; 36 | 37 | /** 38 | * ConnectionFactoryLocator: 查找connectionFactory, 可能有多个QQ,微信等, 会根据条件查找具体实现 39 | * TextEncryptor: 数据加解密工具 40 | */ 41 | @Override 42 | public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) { 43 | JdbcUsersConnectionRepository jdbcUsersConnectionRepository = new JdbcUsersConnectionRepository(dataSource, connectionFactoryLocator, Encryptors.noOpText()); 44 | jdbcUsersConnectionRepository.setTablePrefix(SecurityConstants.DEFAULT_SOCIAL_USER_CONNECTION_PREFIX); 45 | // 根据connection的数据创建userId 46 | if (connectionSignUp != null) { 47 | jdbcUsersConnectionRepository.setConnectionSignUp(connectionSignUp); 48 | } 49 | return jdbcUsersConnectionRepository; 50 | } 51 | 52 | @Bean 53 | public SpringSocialConfigurer imoocSocialSecurityConfig() { 54 | ImoocSpringSocialConfigurer configurer = new ImoocSpringSocialConfigurer(securityProperties.getSocial().getFilterProcessUrl()); 55 | configurer.signupUrl(securityProperties.getBrowser().getSignupPageUrl()); 56 | return configurer; 57 | } 58 | 59 | @Bean 60 | public ProviderSignInUtils providerSignInUtils(ConnectionFactoryLocator connectionFactoryLocator) { 61 | return new ProviderSignInUtils(connectionFactoryLocator, getUsersConnectionRepository(connectionFactoryLocator)); 62 | } 63 | 64 | @Bean("connect/status") 65 | @ConditionalOnMissingBean(name = "connect/status") 66 | public View connectStatusView() { 67 | return new ImoocConnecStatusView(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/social/qq/api/QQ.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.social.qq.api; 2 | 3 | public interface QQ { 4 | QQUserInfo getUserInfo(); 5 | } 6 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/social/qq/api/QQImpl.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.social.qq.api; 2 | 3 | import org.apache.commons.lang.StringUtils; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.social.oauth2.AbstractOAuth2ApiBinding; 7 | import org.springframework.social.oauth2.TokenStrategy; 8 | 9 | import com.fasterxml.jackson.databind.ObjectMapper; 10 | 11 | /** 12 | * QQ访问用户数据获取API接口 13 | * 接口文档: http://wiki.connect.qq.com/get_user_info 14 | * @author lizhuquan 15 | * 16 | */ 17 | public class QQImpl extends AbstractOAuth2ApiBinding implements QQ { 18 | 19 | private Logger logger = LoggerFactory.getLogger(getClass()); 20 | 21 | private static final String URL_GET_OPENID = "https://graph.qq.com/oauth2.0/me?access_token=%s"; 22 | 23 | private static final String URL_GET_USERINFO = "https://graph.qq.com/user/get_user_info?&oauth_consumer_key=%s&openid=%s"; 24 | 25 | private String appId; 26 | 27 | private String openId; 28 | 29 | private ObjectMapper objectMapper = new ObjectMapper(); 30 | 31 | public QQImpl(String accessToken, String appId) { 32 | // restTemplate发请求的时候, qq文档要求accessToken放在url参数上 33 | super(accessToken, TokenStrategy.ACCESS_TOKEN_PARAMETER); 34 | this.appId = appId; 35 | 36 | // 根据accessToken换取openid 37 | String openIdUrl = String.format(URL_GET_OPENID, accessToken); 38 | String openIdResult = getRestTemplate().getForObject(openIdUrl, String.class); 39 | logger.info(openIdResult); 40 | 41 | this.openId = StringUtils.substringBetween(openIdResult, "\"openid\":\"", "\"}"); 42 | } 43 | 44 | // /** 45 | // * 默认注册的StringHttpMessageConverter字符集为ISO-8859-1,而微信返回的是UTF-8的,所以覆盖了原来的方法。 46 | // */ 47 | // protected List> getMessageConverters() { 48 | // List> messageConverters = super.getMessageConverters(); 49 | // messageConverters.remove(0); 50 | // messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8"))); 51 | // return messageConverters; 52 | // } 53 | 54 | @Override 55 | public QQUserInfo getUserInfo() { 56 | String userInfoUrl = String.format(URL_GET_USERINFO, appId, openId); 57 | String userInfoResult = getRestTemplate().getForObject(userInfoUrl, String.class); 58 | logger.info(userInfoResult); 59 | 60 | QQUserInfo userInfo = null; 61 | try { 62 | userInfo = objectMapper.readValue(userInfoResult, QQUserInfo.class); 63 | userInfo.setOpenId(openId); 64 | } catch (Exception e) { 65 | throw new RuntimeException("获取qq用户信息失败"); 66 | } 67 | return userInfo; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/social/qq/api/QQUserInfo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.imooc.security.core.social.qq.api; 5 | 6 | /** 7 | * @author zhailiang 8 | * 9 | */ 10 | public class QQUserInfo { 11 | 12 | /** 13 | * 返回码 14 | */ 15 | private String ret; 16 | /** 17 | * 如果ret<0,会有相应的错误信息提示,返回数据全部用UTF-8编码。 18 | */ 19 | private String msg; 20 | /** 21 | * 22 | */ 23 | private String openId; 24 | /** 25 | * 不知道什么东西,文档上没写,但是实际api返回里有。 26 | */ 27 | private String is_lost; 28 | /** 29 | * 省(直辖市) 30 | */ 31 | private String province; 32 | /** 33 | * 市(直辖市区) 34 | */ 35 | private String city; 36 | /** 37 | * 出生年月 38 | */ 39 | private String year; 40 | /** 41 | * 用户在QQ空间的昵称。 42 | */ 43 | private String nickname; 44 | /** 45 | * 大小为30×30像素的QQ空间头像URL。 46 | */ 47 | private String figureurl; 48 | /** 49 | * 大小为50×50像素的QQ空间头像URL。 50 | */ 51 | private String figureurl_1; 52 | /** 53 | * 大小为100×100像素的QQ空间头像URL。 54 | */ 55 | private String figureurl_2; 56 | /** 57 | * 大小为40×40像素的QQ头像URL。 58 | */ 59 | private String figureurl_qq_1; 60 | /** 61 | * 大小为100×100像素的QQ头像URL。需要注意,不是所有的用户都拥有QQ的100×100的头像,但40×40像素则是一定会有。 62 | */ 63 | private String figureurl_qq_2; 64 | /** 65 | * 性别。 如果获取不到则默认返回”男” 66 | */ 67 | private String gender; 68 | /** 69 | * 标识用户是否为黄钻用户(0:不是;1:是)。 70 | */ 71 | private String is_yellow_vip; 72 | /** 73 | * 标识用户是否为黄钻用户(0:不是;1:是) 74 | */ 75 | private String vip; 76 | /** 77 | * 黄钻等级 78 | */ 79 | private String yellow_vip_level; 80 | /** 81 | * 黄钻等级 82 | */ 83 | private String level; 84 | /** 85 | * 标识是否为年费黄钻用户(0:不是; 1:是) 86 | */ 87 | private String is_yellow_year_vip; 88 | 89 | 90 | public String getRet() { 91 | return ret; 92 | } 93 | public void setRet(String ret) { 94 | this.ret = ret; 95 | } 96 | public String getMsg() { 97 | return msg; 98 | } 99 | public void setMsg(String msg) { 100 | this.msg = msg; 101 | } 102 | public String getOpenId() { 103 | return openId; 104 | } 105 | public void setOpenId(String openId) { 106 | this.openId = openId; 107 | } 108 | public String getIs_lost() { 109 | return is_lost; 110 | } 111 | public void setIs_lost(String is_lost) { 112 | this.is_lost = is_lost; 113 | } 114 | public String getProvince() { 115 | return province; 116 | } 117 | public void setProvince(String province) { 118 | this.province = province; 119 | } 120 | public String getCity() { 121 | return city; 122 | } 123 | public void setCity(String city) { 124 | this.city = city; 125 | } 126 | public String getYear() { 127 | return year; 128 | } 129 | public void setYear(String year) { 130 | this.year = year; 131 | } 132 | public String getNickname() { 133 | return nickname; 134 | } 135 | public void setNickname(String nickname) { 136 | this.nickname = nickname; 137 | } 138 | public String getFigureurl() { 139 | return figureurl; 140 | } 141 | public void setFigureurl(String figureurl) { 142 | this.figureurl = figureurl; 143 | } 144 | public String getFigureurl_1() { 145 | return figureurl_1; 146 | } 147 | public void setFigureurl_1(String figureurl_1) { 148 | this.figureurl_1 = figureurl_1; 149 | } 150 | public String getFigureurl_2() { 151 | return figureurl_2; 152 | } 153 | public void setFigureurl_2(String figureurl_2) { 154 | this.figureurl_2 = figureurl_2; 155 | } 156 | public String getFigureurl_qq_1() { 157 | return figureurl_qq_1; 158 | } 159 | public void setFigureurl_qq_1(String figureurl_qq_1) { 160 | this.figureurl_qq_1 = figureurl_qq_1; 161 | } 162 | public String getFigureurl_qq_2() { 163 | return figureurl_qq_2; 164 | } 165 | public void setFigureurl_qq_2(String figureurl_qq_2) { 166 | this.figureurl_qq_2 = figureurl_qq_2; 167 | } 168 | public String getGender() { 169 | return gender; 170 | } 171 | public void setGender(String gender) { 172 | this.gender = gender; 173 | } 174 | public String getIs_yellow_vip() { 175 | return is_yellow_vip; 176 | } 177 | public void setIs_yellow_vip(String is_yellow_vip) { 178 | this.is_yellow_vip = is_yellow_vip; 179 | } 180 | public String getVip() { 181 | return vip; 182 | } 183 | public void setVip(String vip) { 184 | this.vip = vip; 185 | } 186 | public String getYellow_vip_level() { 187 | return yellow_vip_level; 188 | } 189 | public void setYellow_vip_level(String yellow_vip_level) { 190 | this.yellow_vip_level = yellow_vip_level; 191 | } 192 | public String getLevel() { 193 | return level; 194 | } 195 | public void setLevel(String level) { 196 | this.level = level; 197 | } 198 | public String getIs_yellow_year_vip() { 199 | return is_yellow_year_vip; 200 | } 201 | public void setIs_yellow_year_vip(String is_yellow_year_vip) { 202 | this.is_yellow_year_vip = is_yellow_year_vip; 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/social/qq/config/QQAutoConfig.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.social.qq.config; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.core.env.Environment; 9 | import org.springframework.social.UserIdSource; 10 | import org.springframework.social.config.annotation.ConnectionFactoryConfigurer; 11 | import org.springframework.social.config.annotation.SocialConfigurer; 12 | import org.springframework.social.connect.ConnectionFactoryLocator; 13 | import org.springframework.social.connect.UsersConnectionRepository; 14 | import org.springframework.web.servlet.View; 15 | 16 | import com.imooc.security.core.properties.QQProperties; 17 | import com.imooc.security.core.properties.SecurityProperties; 18 | import com.imooc.security.core.social.qq.connect.QQConnectionFactory; 19 | import com.imooc.security.core.social.view.ImoocConnectedView; 20 | 21 | @Configuration 22 | @ConditionalOnProperty(prefix = "imooc.security.social.qq", name = "app-id") 23 | public class QQAutoConfig implements SocialConfigurer { 24 | 25 | @Autowired 26 | private SecurityProperties securityProperties; 27 | 28 | /** 29 | * UsersConnectionRepository有主配置SocialConfig提供 30 | */ 31 | @Override 32 | public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) { 33 | return null; 34 | } 35 | 36 | @Override 37 | public void addConnectionFactories(ConnectionFactoryConfigurer connectionFactoryConfigurer, Environment environment) { 38 | QQProperties qqConfig = securityProperties.getSocial().getQq(); 39 | QQConnectionFactory connectionFactory = new QQConnectionFactory(qqConfig.getProviderId(), qqConfig.getAppId(), qqConfig.getAppSecret()); 40 | connectionFactoryConfigurer.addConnectionFactory(connectionFactory); 41 | } 42 | 43 | @Override 44 | public UserIdSource getUserIdSource() { 45 | return null; 46 | } 47 | 48 | @Bean(name = {"connect/qqConnect", "connect/qqConnected"}) 49 | @ConditionalOnMissingBean(name = {"connect/qqConnect", "connect/qqConnected"}) 50 | public View qqConnectedView() { 51 | return new ImoocConnectedView(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/social/qq/connect/QQAdapter.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.social.qq.connect; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.social.connect.ApiAdapter; 6 | import org.springframework.social.connect.ConnectionValues; 7 | import org.springframework.social.connect.UserProfile; 8 | 9 | import com.imooc.security.core.social.qq.api.QQ; 10 | import com.imooc.security.core.social.qq.api.QQUserInfo; 11 | 12 | /** 13 | * 1. 给三方用户数据做适配转换 14 | * @author Administrator 15 | * 16 | */ 17 | public class QQAdapter implements ApiAdapter{ 18 | 19 | private Logger logger = LoggerFactory.getLogger(getClass()); 20 | 21 | @Override 22 | public boolean test(QQ api) { 23 | return true; 24 | } 25 | 26 | @Override 27 | public void setConnectionValues(QQ api, ConnectionValues values) { 28 | QQUserInfo userInfo = api.getUserInfo(); 29 | logger.info("QQImpl调用获取用户信息: " + userInfo.toString()); 30 | 31 | values.setDisplayName(userInfo.getNickname()); // 昵称 32 | values.setImageUrl(userInfo.getFigureurl()); // 图像url 33 | values.setProfileUrl(null); //个人主页 34 | values.setProviderUserId(userInfo.getOpenId()); // openid 35 | } 36 | 37 | @Override 38 | public UserProfile fetchUserProfile(QQ api) { 39 | return null; 40 | } 41 | 42 | @Override 43 | public void updateStatus(QQ api, String message) { 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/social/qq/connect/QQConnectionFactory.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.social.qq.connect; 2 | 3 | import org.springframework.social.connect.support.OAuth2ConnectionFactory; 4 | 5 | import com.imooc.security.core.social.qq.api.QQ; 6 | 7 | /** 8 | * 1. 产生connection, 然后connection会被封装成SocialAuthenticationToke 9 | * @author Administrator 10 | * 11 | */ 12 | public class QQConnectionFactory extends OAuth2ConnectionFactory{ 13 | 14 | public QQConnectionFactory(String providerId, String appId, String appSecret) { 15 | super(providerId, new QQServiceProvider(appId, appSecret), new QQAdapter()); 16 | } 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/social/qq/connect/QQOAuth2Template.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.social.qq.connect; 2 | 3 | import java.nio.charset.Charset; 4 | 5 | import org.apache.commons.lang.StringUtils; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.http.converter.StringHttpMessageConverter; 9 | import org.springframework.social.oauth2.AccessGrant; 10 | import org.springframework.social.oauth2.OAuth2Template; 11 | import org.springframework.util.MultiValueMap; 12 | import org.springframework.web.client.RestTemplate; 13 | 14 | public class QQOAuth2Template extends OAuth2Template { 15 | 16 | private Logger logger = LoggerFactory.getLogger(getClass()); 17 | 18 | public QQOAuth2Template(String clientId, String clientSecret, String authorizeUrl, String accessTokenUrl) { 19 | super(clientId, clientSecret, authorizeUrl, accessTokenUrl); 20 | setUseParametersForClientAuthentication(true); 21 | } 22 | 23 | @Override 24 | protected AccessGrant postForAccessGrant(String accessTokenUrl, MultiValueMap parameters) { 25 | String responseStr = getRestTemplate().postForObject(accessTokenUrl, parameters, String.class); 26 | logger.info("发送的accessTokenUrl:" + accessTokenUrl); 27 | logger.info("获取accessToken的响应:" + responseStr); 28 | 29 | String[] items = StringUtils.splitByWholeSeparator(responseStr, "&"); 30 | 31 | String accessToken = StringUtils.substringAfterLast(items[0], "="); 32 | Long expiresIn = new Long(StringUtils.substringAfterLast(items[1], "=")); 33 | String refreshToken = StringUtils.substringAfterLast(items[2], "="); 34 | 35 | return new AccessGrant(accessToken, null, refreshToken, expiresIn); 36 | } 37 | 38 | @Override 39 | protected RestTemplate createRestTemplate() { 40 | RestTemplate restTemplate = super.createRestTemplate(); 41 | restTemplate.getMessageConverters().add(new StringHttpMessageConverter(Charset.forName("UTF-8"))); 42 | return restTemplate; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/social/qq/connect/QQServiceProvider.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.social.qq.connect; 2 | 3 | import org.springframework.social.oauth2.AbstractOAuth2ServiceProvider; 4 | 5 | import com.imooc.security.core.social.qq.api.QQ; 6 | import com.imooc.security.core.social.qq.api.QQImpl; 7 | 8 | /** 9 | * 1. 使用OAuth2Template执行流程 10 | * 2. 使用QQImple获取三方用户数据 11 | * @author Administrator 12 | * 13 | */ 14 | public class QQServiceProvider extends AbstractOAuth2ServiceProvider { 15 | 16 | private static final String URL_AUTHORIZE = "https://graph.qq.com/oauth2.0/authorize"; 17 | 18 | private static final String URL_ACCESSTOKEN = "https://graph.qq.com/oauth2.0/token"; 19 | 20 | private String appId; 21 | 22 | 23 | public QQServiceProvider(String appId, String appSecret) { 24 | // authorizeUrl 用户导向url 25 | // accessTokenUrl 申请令牌地址 26 | super(new QQOAuth2Template(appId, appSecret, URL_AUTHORIZE, URL_ACCESSTOKEN)); 27 | this.appId = appId; 28 | } 29 | 30 | @Override 31 | public QQ getApi(String accessToken) { 32 | return new QQImpl(accessToken, appId); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/social/view/ImoocConnecStatusView.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.social.view; 2 | 3 | import java.util.HashMap; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.servlet.http.HttpServletResponse; 9 | 10 | import org.apache.commons.collections.CollectionUtils; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.social.connect.Connection; 13 | import org.springframework.web.servlet.view.AbstractView; 14 | 15 | import com.fasterxml.jackson.databind.ObjectMapper; 16 | 17 | public class ImoocConnecStatusView extends AbstractView { 18 | 19 | @Autowired 20 | private ObjectMapper objectMapper; 21 | 22 | @Override 23 | protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) 24 | throws Exception { 25 | 26 | @SuppressWarnings("unchecked") 27 | Map>> connections = (Map>>) model.get("connectionMap"); 28 | 29 | Map result = new HashMap<>(); 30 | for (String key : connections.keySet()) { 31 | result.put(key, CollectionUtils.isNotEmpty(connections.get(key))); 32 | } 33 | 34 | response.setContentType("application/json;charset=UTF=8"); 35 | response.getWriter().write(objectMapper.writeValueAsString(result)); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/social/view/ImoocConnectedView.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.social.view; 2 | 3 | import java.util.Map; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | 8 | import org.springframework.web.servlet.view.AbstractView; 9 | 10 | public class ImoocConnectedView extends AbstractView { 11 | 12 | @Override 13 | protected void renderMergedOutputModel(Map model, HttpServletRequest request, 14 | HttpServletResponse response) throws Exception { 15 | response.setContentType("text/plain;charset=UTF-8"); 16 | if (model.get("connections") == null) { 17 | response.getWriter().write("imooc 解绑成功"); 18 | } else { 19 | response.getWriter().write("imooc 绑定成功"); 20 | } 21 | 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/social/weixin/api/Weixin.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.social.weixin.api; 2 | 3 | public interface Weixin { 4 | 5 | WeixinUserInfo getUserInfo(String openId); 6 | } 7 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/social/weixin/api/WeixinImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.imooc.security.core.social.weixin.api; 5 | 6 | import java.nio.charset.Charset; 7 | import java.util.List; 8 | 9 | import org.apache.commons.lang.StringUtils; 10 | import org.springframework.http.converter.HttpMessageConverter; 11 | import org.springframework.http.converter.StringHttpMessageConverter; 12 | import org.springframework.social.oauth2.AbstractOAuth2ApiBinding; 13 | import org.springframework.social.oauth2.TokenStrategy; 14 | 15 | import com.fasterxml.jackson.databind.ObjectMapper; 16 | 17 | /** 18 | * Weixin API调用模板, scope为Request的Spring bean, 根据当前用户的accessToken创建。 19 | * 20 | * @author zhailiang 21 | * 22 | */ 23 | public class WeixinImpl extends AbstractOAuth2ApiBinding implements Weixin { 24 | 25 | /** 26 | * 27 | */ 28 | private ObjectMapper objectMapper = new ObjectMapper(); 29 | /** 30 | * 获取用户信息的url 31 | */ 32 | private static final String URL_GET_USER_INFO = "https://api.weixin.qq.com/sns/userinfo?openid="; 33 | 34 | /** 35 | * @param accessToken 36 | */ 37 | public WeixinImpl(String accessToken) { 38 | super(accessToken, TokenStrategy.ACCESS_TOKEN_PARAMETER); 39 | } 40 | 41 | /** 42 | * 默认注册的StringHttpMessageConverter字符集为ISO-8859-1,而微信返回的是UTF-8的,所以覆盖了原来的方法。 43 | */ 44 | protected List> getMessageConverters() { 45 | List> messageConverters = super.getMessageConverters(); 46 | messageConverters.remove(0); 47 | messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8"))); 48 | return messageConverters; 49 | } 50 | 51 | /** 52 | * 获取微信用户信息。 53 | */ 54 | @Override 55 | public WeixinUserInfo getUserInfo(String openId) { 56 | String url = URL_GET_USER_INFO + openId; 57 | String response = getRestTemplate().getForObject(url, String.class); 58 | if(StringUtils.contains(response, "errcode")) { 59 | return null; 60 | } 61 | WeixinUserInfo profile = null; 62 | try { 63 | profile = objectMapper.readValue(response, WeixinUserInfo.class); 64 | } catch (Exception e) { 65 | e.printStackTrace(); 66 | } 67 | return profile; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/social/weixin/api/WeixinUserInfo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.imooc.security.core.social.weixin.api; 5 | 6 | /** 7 | * 微信用户信息 8 | * 9 | * @author zhailiang 10 | */ 11 | public class WeixinUserInfo { 12 | 13 | /** 14 | * 普通用户的标识,对当前开发者帐号唯一 15 | */ 16 | private String openid; 17 | /** 18 | * 普通用户昵称 19 | */ 20 | private String nickname; 21 | /** 22 | * 语言 23 | */ 24 | private String language; 25 | /** 26 | * 普通用户性别,1为男性,2为女性 27 | */ 28 | private String sex; 29 | /** 30 | * 普通用户个人资料填写的省份 31 | */ 32 | private String province; 33 | /** 34 | * 普通用户个人资料填写的城市 35 | */ 36 | private String city; 37 | /** 38 | * 国家,如中国为CN 39 | */ 40 | private String country; 41 | /** 42 | * 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空 43 | */ 44 | private String headimgurl; 45 | /** 46 | * 用户特权信息,json数组,如微信沃卡用户为(chinaunicom) 47 | */ 48 | private String[] privilege; 49 | /** 50 | * 用户统一标识。针对一个微信开放平台帐号下的应用,同一用户的unionid是唯一的。 51 | */ 52 | private String unionid; 53 | 54 | /** 55 | * @return the openid 56 | */ 57 | public String getOpenid() { 58 | return openid; 59 | } 60 | /** 61 | * @param openid the openid to set 62 | */ 63 | public void setOpenid(String openid) { 64 | this.openid = openid; 65 | } 66 | /** 67 | * @return the nickname 68 | */ 69 | public String getNickname() { 70 | return nickname; 71 | } 72 | /** 73 | * @param nickname the nickname to set 74 | */ 75 | public void setNickname(String nickname) { 76 | this.nickname = nickname; 77 | } 78 | /** 79 | * @return the sex 80 | */ 81 | public String getSex() { 82 | return sex; 83 | } 84 | /** 85 | * @param sex the sex to set 86 | */ 87 | public void setSex(String sex) { 88 | this.sex = sex; 89 | } 90 | /** 91 | * @return the province 92 | */ 93 | public String getProvince() { 94 | return province; 95 | } 96 | /** 97 | * @param province the province to set 98 | */ 99 | public void setProvince(String province) { 100 | this.province = province; 101 | } 102 | /** 103 | * @return the city 104 | */ 105 | public String getCity() { 106 | return city; 107 | } 108 | /** 109 | * @param city the city to set 110 | */ 111 | public void setCity(String city) { 112 | this.city = city; 113 | } 114 | /** 115 | * @return the country 116 | */ 117 | public String getCountry() { 118 | return country; 119 | } 120 | /** 121 | * @param country the country to set 122 | */ 123 | public void setCountry(String country) { 124 | this.country = country; 125 | } 126 | /** 127 | * @return the headimgurl 128 | */ 129 | public String getHeadimgurl() { 130 | return headimgurl; 131 | } 132 | /** 133 | * @param headimgurl the headimgurl to set 134 | */ 135 | public void setHeadimgurl(String headimgurl) { 136 | this.headimgurl = headimgurl; 137 | } 138 | /** 139 | * @return the privilege 140 | */ 141 | public String[] getPrivilege() { 142 | return privilege; 143 | } 144 | /** 145 | * @param privilege the privilege to set 146 | */ 147 | public void setPrivilege(String[] privilege) { 148 | this.privilege = privilege; 149 | } 150 | /** 151 | * @return the unionid 152 | */ 153 | public String getUnionid() { 154 | return unionid; 155 | } 156 | /** 157 | * @param unionid the unionid to set 158 | */ 159 | public void setUnionid(String unionid) { 160 | this.unionid = unionid; 161 | } 162 | /** 163 | * @return the language 164 | */ 165 | public String getLanguage() { 166 | return language; 167 | } 168 | /** 169 | * @param language the language to set 170 | */ 171 | public void setLanguage(String language) { 172 | this.language = language; 173 | } 174 | 175 | } 176 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/support/SimpleResponse.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.support; 2 | 3 | public class SimpleResponse { 4 | 5 | private Object content; 6 | 7 | public SimpleResponse(Object content) { 8 | this.content = content; 9 | } 10 | 11 | public Object getContent() { 12 | return content; 13 | } 14 | 15 | public void setContent(Object content) { 16 | this.content = content; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/support/SocialUserInfo.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.support; 2 | 3 | public class SocialUserInfo { 4 | private String providerId; 5 | 6 | private String providerUserId; 7 | 8 | private String nickname; 9 | 10 | private String headimg; 11 | 12 | public String getProviderId() { 13 | return providerId; 14 | } 15 | 16 | public void setProviderId(String providerId) { 17 | this.providerId = providerId; 18 | } 19 | 20 | public String getProviderUserId() { 21 | return providerUserId; 22 | } 23 | 24 | public void setProviderUserId(String providerUserId) { 25 | this.providerUserId = providerUserId; 26 | } 27 | 28 | public String getNickname() { 29 | return nickname; 30 | } 31 | 32 | public void setNickname(String nickname) { 33 | this.nickname = nickname; 34 | } 35 | 36 | public String getHeadimg() { 37 | return headimg; 38 | } 39 | 40 | public void setHeadimg(String headimg) { 41 | this.headimg = headimg; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/validate/code/AbstractValidateCodeProcessor.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.validate.code; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.web.context.request.ServletWebRequest; 5 | 6 | import com.imooc.security.core.properties.contsant.ValidateCodeTypeEnum; 7 | import com.imooc.security.core.validate.code.image.ImageCode; 8 | import com.imooc.security.core.validate.code.sms.SmsCode; 9 | 10 | public abstract class AbstractValidateCodeProcessor implements ValidateCodeProcessor { 11 | 12 | @Autowired 13 | private ValidateCodeRepository validateCodeRepository; 14 | 15 | @Override 16 | public void process(ServletWebRequest request) throws Exception { 17 | C validateCode = generate(request); 18 | save(request, validateCode); 19 | send(request, validateCode); 20 | } 21 | 22 | private void save(ServletWebRequest request, C validateCode) { 23 | ValidateCode codeToSave = new ValidateCode(validateCode.getCode(), validateCode.getExpireTime()); 24 | validateCodeRepository.save(request, codeToSave, getValidateCodeType(validateCode)); 25 | } 26 | 27 | @SuppressWarnings("unchecked") 28 | private C generate(ServletWebRequest request) throws Exception { 29 | return (C) getValidateCodeGenerator().generate(request); 30 | } 31 | 32 | private ValidateCodeTypeEnum getValidateCodeType(ValidateCode validateCode) { 33 | if (validateCode instanceof ImageCode) { 34 | return ValidateCodeTypeEnum.IMAGE; 35 | } else if (validateCode instanceof SmsCode) { 36 | return ValidateCodeTypeEnum.SMS; 37 | } else { 38 | throw new ValidateCodeException("不支持的validateCode类型" + validateCode.getClass().getCanonicalName()); 39 | } 40 | } 41 | 42 | protected abstract G getValidateCodeGenerator(); 43 | 44 | protected abstract void send(ServletWebRequest request, C validateCode) throws Exception; 45 | } 46 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/validate/code/HttpSessionValidateCodeRepository.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.validate.code; 2 | 3 | import org.springframework.social.connect.web.HttpSessionSessionStrategy; 4 | import org.springframework.social.connect.web.SessionStrategy; 5 | import org.springframework.web.context.request.ServletWebRequest; 6 | 7 | import com.imooc.security.core.properties.contsant.ValidateCodeTypeEnum; 8 | import com.imooc.security.core.validate.code.ValidateCode; 9 | import com.imooc.security.core.validate.code.ValidateCodeRepository; 10 | 11 | public class HttpSessionValidateCodeRepository implements ValidateCodeRepository { 12 | 13 | public final static String VALIDATECODE_SESSIONKEY_PREFIX = "SESSION_KEY_FOR_CODE_"; 14 | 15 | private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); 16 | 17 | @Override 18 | public void save(ServletWebRequest request, ValidateCode code, ValidateCodeTypeEnum codeType) { 19 | sessionStrategy.setAttribute(request, getSessionKey(codeType), code); 20 | } 21 | 22 | @Override 23 | public ValidateCode get(ServletWebRequest request, ValidateCodeTypeEnum codeType) { 24 | Object objectInSession = sessionStrategy.getAttribute(request, getSessionKey(codeType)); 25 | if (objectInSession != null) { 26 | return (ValidateCode) objectInSession; 27 | } else { 28 | return null; 29 | } 30 | } 31 | 32 | @Override 33 | public void remove(ServletWebRequest request, ValidateCodeTypeEnum codeType) { 34 | sessionStrategy.removeAttribute(request, getSessionKey(codeType)); 35 | } 36 | 37 | private String getSessionKey(ValidateCodeTypeEnum codeType) { 38 | StringBuilder buff = new StringBuilder(VALIDATECODE_SESSIONKEY_PREFIX); 39 | buff.append(codeType); 40 | return buff.toString(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/validate/code/RedisValidateCodeRepository.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.validate.code; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.data.redis.core.RedisTemplate; 7 | import org.springframework.web.context.request.ServletWebRequest; 8 | 9 | import com.imooc.security.core.properties.contsant.ValidateCodeTypeEnum; 10 | 11 | public class RedisValidateCodeRepository implements ValidateCodeRepository { 12 | 13 | public static final String DEVICEID_HEADER_NAME = "deviceId"; 14 | 15 | public static final String VALIDATECODE_REDISKEY_PREFIX = "code:"; 16 | 17 | @Autowired 18 | private RedisTemplate redisTemplate; 19 | 20 | @Override 21 | public void save(ServletWebRequest request, ValidateCode code, ValidateCodeTypeEnum codeType) { 22 | redisTemplate.opsForValue().set(getRedisKey(request, codeType), code, 30, TimeUnit.MINUTES); 23 | } 24 | 25 | @Override 26 | public ValidateCode get(ServletWebRequest request, ValidateCodeTypeEnum codeType) { 27 | Object codeInRedis = redisTemplate.opsForValue().get(getRedisKey(request, codeType)); 28 | if (codeInRedis != null) { 29 | return (ValidateCode) codeInRedis; 30 | } else { 31 | return null; 32 | } 33 | } 34 | 35 | @Override 36 | public void remove(ServletWebRequest request, ValidateCodeTypeEnum codeType) { 37 | redisTemplate.delete(getRedisKey(request, codeType)); 38 | } 39 | 40 | private String getRedisKey(ServletWebRequest request, ValidateCodeTypeEnum codeType) { 41 | String deviceId = getDeviceId(request); 42 | StringBuilder buff = new StringBuilder(VALIDATECODE_REDISKEY_PREFIX); 43 | buff.append(codeType).append(":").append(deviceId); 44 | return buff.toString(); 45 | } 46 | 47 | private String getDeviceId(ServletWebRequest request) { 48 | String deviceId = request.getHeader(DEVICEID_HEADER_NAME); 49 | if (deviceId == null) { 50 | throw new ValidateCodeException("缺少deviceId"); 51 | } 52 | return deviceId; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/validate/code/ValidateCode.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.validate.code; 2 | 3 | import java.io.Serializable; 4 | import java.time.LocalDateTime; 5 | 6 | /** 7 | * 所有验证码实体类的父类 8 | * @author lizhuquan 9 | * 10 | */ 11 | public class ValidateCode implements Serializable { 12 | 13 | /** 14 | * 15 | */ 16 | private static final long serialVersionUID = 1L; 17 | 18 | protected String code; 19 | 20 | protected LocalDateTime expireTime; 21 | 22 | public ValidateCode(String code, int expireIn) { 23 | this.code = code; 24 | this.expireTime = LocalDateTime.now().plusSeconds(expireIn); 25 | } 26 | 27 | public ValidateCode(String code, LocalDateTime expireTime) { 28 | this.code = code; 29 | this.expireTime = expireTime; 30 | } 31 | 32 | public boolean isExpired() { 33 | return expireTime.isBefore(LocalDateTime.now()); 34 | } 35 | 36 | public String getCode() { 37 | return code; 38 | } 39 | 40 | public void setCode(String code) { 41 | this.code = code; 42 | } 43 | 44 | public LocalDateTime getExpireTime() { 45 | return expireTime; 46 | } 47 | 48 | public void setExpireTime(LocalDateTime expireTime) { 49 | this.expireTime = expireTime; 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return "ValidateCode [code=" + code + ", expireTime=" + expireTime + "]"; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/validate/code/ValidateCodeController.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.validate.code; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import javax.servlet.http.HttpServletResponse; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import org.springframework.web.context.request.ServletWebRequest; 10 | 11 | import com.imooc.security.core.validate.code.image.ImageCodeProcessor; 12 | import com.imooc.security.core.validate.code.sms.SmsCodeProcessor; 13 | 14 | @RestController 15 | public class ValidateCodeController { 16 | 17 | @Autowired 18 | private ImageCodeProcessor imageCodeProcessor; 19 | 20 | @Autowired 21 | private SmsCodeProcessor smsCodeProcessor; 22 | 23 | 24 | @GetMapping("#{globalSecurityProperties.browser.validateCodeUrlImage}") 25 | public void createImageCode(HttpServletRequest request, HttpServletResponse response) throws Exception { 26 | imageCodeProcessor.process(new ServletWebRequest(request, response)); 27 | } 28 | 29 | @GetMapping(value = "#{globalSecurityProperties.browser.validateCodeUrlSms}", params = {"mobile"}) 30 | public void createSmsCode(HttpServletRequest request, HttpServletResponse response) throws Exception { 31 | smsCodeProcessor.process(new ServletWebRequest(request, response)); 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/validate/code/ValidateCodeException.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.validate.code; 2 | 3 | import org.springframework.security.core.AuthenticationException; 4 | 5 | public class ValidateCodeException extends AuthenticationException { 6 | 7 | /** 8 | * 9 | */ 10 | private static final long serialVersionUID = 1L; 11 | 12 | public ValidateCodeException(String msg) { 13 | super(msg); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/validate/code/ValidateCodeGenerator.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.validate.code; 2 | 3 | import org.springframework.web.context.request.ServletWebRequest; 4 | 5 | public interface ValidateCodeGenerator { 6 | 7 | ValidateCode generate(ServletWebRequest request); 8 | } 9 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/validate/code/ValidateCodeProcessor.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.validate.code; 2 | 3 | import org.springframework.web.context.request.ServletWebRequest; 4 | 5 | public interface ValidateCodeProcessor { 6 | 7 | /** 8 | * 处理 9 | * @param request 10 | * @throws Exception 11 | */ 12 | void process(ServletWebRequest request) throws Exception; 13 | } 14 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/validate/code/ValidateCodeRepository.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.validate.code; 2 | 3 | import org.springframework.web.context.request.ServletWebRequest; 4 | 5 | import com.imooc.security.core.properties.contsant.ValidateCodeTypeEnum; 6 | 7 | public interface ValidateCodeRepository { 8 | 9 | void save(ServletWebRequest request, ValidateCode code, ValidateCodeTypeEnum codeType); 10 | 11 | ValidateCode get(ServletWebRequest request, ValidateCodeTypeEnum codeType); 12 | 13 | void remove(ServletWebRequest request, ValidateCodeTypeEnum codeType); 14 | } 15 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/validate/code/ValidateCodeSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.validate.code; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.security.config.annotation.SecurityConfigurerAdapter; 5 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 6 | import org.springframework.security.web.DefaultSecurityFilterChain; 7 | import org.springframework.security.web.authentication.AuthenticationFailureHandler; 8 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; 9 | import org.springframework.stereotype.Component; 10 | 11 | import com.imooc.security.core.properties.SecurityProperties; 12 | 13 | @Component 14 | public class ValidateCodeSecurityConfig extends SecurityConfigurerAdapter { 15 | 16 | @Autowired 17 | private SecurityProperties securityProperties; 18 | 19 | @Autowired 20 | private AuthenticationFailureHandler authenticationFailureHandler; 21 | 22 | @Autowired 23 | private ValidateCodeRepository validateCodeRepository; 24 | 25 | @Override 26 | public void configure(HttpSecurity http) throws Exception { 27 | 28 | ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter(); 29 | validateCodeFilter.setValidateCodeRepository(validateCodeRepository); 30 | validateCodeFilter.setAuthenticationFailureHandler(authenticationFailureHandler); 31 | validateCodeFilter.setSecurityProperties(securityProperties); 32 | validateCodeFilter.afterPropertiesSet(); 33 | 34 | http 35 | .addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/validate/code/image/DefaultImageCodeGenerator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.imooc.security.core.validate.code.image; 5 | 6 | import java.awt.Color; 7 | import java.awt.Font; 8 | import java.awt.Graphics; 9 | import java.awt.image.BufferedImage; 10 | import java.util.Random; 11 | 12 | import org.springframework.web.bind.ServletRequestUtils; 13 | import org.springframework.web.context.request.ServletWebRequest; 14 | 15 | import com.imooc.security.core.properties.SecurityProperties; 16 | 17 | public class DefaultImageCodeGenerator implements ImageCodeGenerator { 18 | 19 | private SecurityProperties securityProperties; 20 | 21 | @Override 22 | public ImageCode generate(ServletWebRequest request) { 23 | int width = ServletRequestUtils.getIntParameter(request.getRequest(), "width", 24 | securityProperties.getCode().getImage().getWidth()); 25 | int height = ServletRequestUtils.getIntParameter(request.getRequest(), "height", 26 | securityProperties.getCode().getImage().getHeight()); 27 | BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 28 | 29 | Graphics g = image.getGraphics(); 30 | 31 | Random random = new Random(); 32 | 33 | g.setColor(getRandColor(200, 250)); 34 | g.fillRect(0, 0, width, height); 35 | g.setFont(new Font("Times New Roman", Font.ITALIC, 20)); 36 | g.setColor(getRandColor(160, 200)); 37 | for (int i = 0; i < 155; i++) { 38 | int x = random.nextInt(width); 39 | int y = random.nextInt(height); 40 | int xl = random.nextInt(12); 41 | int yl = random.nextInt(12); 42 | g.drawLine(x, y, x + xl, y + yl); 43 | } 44 | 45 | String sRand = ""; 46 | for (int i = 0; i < securityProperties.getCode().getImage().getLength(); i++) { 47 | String rand = String.valueOf(random.nextInt(10)); 48 | sRand += rand; 49 | g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110))); 50 | g.drawString(rand, 13 * i + 6, 16); 51 | } 52 | 53 | g.dispose(); 54 | 55 | return new ImageCode(image, sRand, securityProperties.getCode().getImage().getExpireIn()); 56 | } 57 | 58 | /** 59 | * 生成随机背景条纹 60 | * 61 | * @param fc 62 | * @param bc 63 | * @return 64 | */ 65 | private Color getRandColor(int fc, int bc) { 66 | Random random = new Random(); 67 | if (fc > 255) { 68 | fc = 255; 69 | } 70 | if (bc > 255) { 71 | bc = 255; 72 | } 73 | int r = fc + random.nextInt(bc - fc); 74 | int g = fc + random.nextInt(bc - fc); 75 | int b = fc + random.nextInt(bc - fc); 76 | return new Color(r, g, b); 77 | } 78 | 79 | public void setSecurityProperties(SecurityProperties securityProperties) { 80 | this.securityProperties = securityProperties; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/validate/code/image/ImageCode.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.validate.code.image; 2 | 3 | import java.awt.image.BufferedImage; 4 | import java.time.LocalDateTime; 5 | 6 | import com.imooc.security.core.validate.code.ValidateCode; 7 | 8 | public class ImageCode extends ValidateCode { 9 | 10 | /** 11 | * 12 | */ 13 | private static final long serialVersionUID = 1L; 14 | 15 | private BufferedImage image; 16 | 17 | public ImageCode(BufferedImage image, String code, int expireIn) { 18 | super(code, expireIn); 19 | this.image = image; 20 | } 21 | 22 | public ImageCode(BufferedImage image, String code, LocalDateTime expireTime) { 23 | super(code, expireTime); 24 | this.image = image; 25 | } 26 | 27 | public BufferedImage getImage() { 28 | return image; 29 | } 30 | 31 | public void setImage(BufferedImage image) { 32 | this.image = image; 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | return "ImageCode [" + "code=" + code + ", expireTime=" + expireTime + "]"; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/validate/code/image/ImageCodeGenerator.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.validate.code.image; 2 | 3 | import com.imooc.security.core.validate.code.ValidateCodeGenerator; 4 | 5 | public interface ImageCodeGenerator extends ValidateCodeGenerator { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/validate/code/image/ImageCodeProcessor.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.validate.code.image; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.imageio.ImageIO; 6 | 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Component; 9 | import org.springframework.web.context.request.ServletWebRequest; 10 | 11 | import com.imooc.security.core.validate.code.AbstractValidateCodeProcessor; 12 | 13 | @Component 14 | public class ImageCodeProcessor extends AbstractValidateCodeProcessor{ 15 | 16 | @Autowired 17 | private ImageCodeGenerator imageCodeGenerator; 18 | 19 | @Override 20 | protected ImageCodeGenerator getValidateCodeGenerator() { 21 | return imageCodeGenerator; 22 | } 23 | 24 | @Override 25 | protected void send(ServletWebRequest request, ImageCode validateCode) throws IOException { 26 | request.getResponse().addHeader("Content-Type", "image/jpeg"); 27 | ImageIO.write(validateCode.getImage(), "JPEG", request.getResponse().getOutputStream()); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/validate/code/sms/DefaultSmsCodeGenerator.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.validate.code.sms; 2 | 3 | import org.apache.commons.lang.RandomStringUtils; 4 | import org.springframework.web.context.request.ServletWebRequest; 5 | 6 | import com.imooc.security.core.properties.SecurityProperties; 7 | 8 | public class DefaultSmsCodeGenerator implements SmsCodeGenerator { 9 | 10 | private SecurityProperties securityProperties; 11 | 12 | @Override 13 | public SmsCode generate(ServletWebRequest request) { 14 | String code = RandomStringUtils.randomNumeric(securityProperties.getCode().getSms().getLength()); 15 | return new SmsCode(code, securityProperties.getCode().getSms().getExpireIn()); 16 | } 17 | 18 | public void setSecurityProperties(SecurityProperties securityProperties) { 19 | this.securityProperties = securityProperties; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/validate/code/sms/DefaultSmsCodeSender.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.validate.code.sms; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | public class DefaultSmsCodeSender implements SmsCodeSender { 7 | 8 | private Logger logger = LoggerFactory.getLogger(getClass()); 9 | 10 | @Override 11 | public void send(String mobile, String code) { 12 | logger.info(String.format("向手机%s发送验证码%s", mobile, code)); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/validate/code/sms/SmsCode.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.validate.code.sms; 2 | 3 | import java.time.LocalDateTime; 4 | 5 | import com.imooc.security.core.validate.code.ValidateCode; 6 | 7 | public class SmsCode extends ValidateCode { 8 | 9 | /** 10 | * 11 | */ 12 | private static final long serialVersionUID = 1L; 13 | 14 | public SmsCode(String code, int expireIn) { 15 | super(code, expireIn); 16 | } 17 | 18 | public SmsCode(String code, LocalDateTime expireTime) { 19 | super(code, expireTime); 20 | } 21 | 22 | @Override 23 | public String toString() { 24 | return "SmsCode [code=" + code + ", expireTime=" + expireTime + "]"; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/validate/code/sms/SmsCodeGenerator.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.validate.code.sms; 2 | 3 | import com.imooc.security.core.validate.code.ValidateCodeGenerator; 4 | 5 | public interface SmsCodeGenerator extends ValidateCodeGenerator { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/validate/code/sms/SmsCodeProcessor.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.validate.code.sms; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Component; 5 | import org.springframework.web.bind.ServletRequestUtils; 6 | import org.springframework.web.context.request.ServletWebRequest; 7 | 8 | import com.imooc.security.core.validate.code.AbstractValidateCodeProcessor; 9 | 10 | @Component 11 | public class SmsCodeProcessor extends AbstractValidateCodeProcessor{ 12 | 13 | @Autowired 14 | private SmsCodeGenerator smsCodeGenerator; 15 | 16 | @Autowired 17 | private SmsCodeSender smsCodeSender; 18 | 19 | @Override 20 | protected SmsCodeGenerator getValidateCodeGenerator() { 21 | return smsCodeGenerator; 22 | } 23 | 24 | @Override 25 | protected void send(ServletWebRequest request, SmsCode validateCode) throws Exception { 26 | String mobile = ServletRequestUtils.getStringParameter(request.getRequest(), "mobile"); 27 | smsCodeSender.send(mobile, validateCode.getCode()); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /imooc-security-core/src/main/java/com/imooc/security/core/validate/code/sms/SmsCodeSender.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security.core.validate.code.sms; 2 | 3 | public interface SmsCodeSender { 4 | void send(String mobile, String code); 5 | } 6 | -------------------------------------------------------------------------------- /imooc-security-demo/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | 3 | /.apt_generated/ 4 | 5 | 6 | .factorypath -------------------------------------------------------------------------------- /imooc-security-demo/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | imooc-security-demo 5 | 6 | com.imooc.security 7 | imooc-security 8 | 0.0.1-SNAPSHOT 9 | 10 | ${imooc.security.version} 11 | 12 | 13 | 14 | com.imooc.security 15 | imooc-security-browser 16 | ${imooc.security.version} 17 | 18 | 23 | 24 | com.imooc.security 25 | imooc-security-authorize 26 | ${imooc.security.version} 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-test 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-aop 35 | 36 | 37 | commons-io 38 | commons-io 39 | 40 | 41 | io.springfox 42 | springfox-swagger2 43 | 2.7.0 44 | 45 | 46 | io.springfox 47 | springfox-swagger-ui 48 | 2.7.0 49 | 50 | 51 | com.github.tomakehurst 52 | wiremock 53 | 54 | 55 | org.apache.httpcomponents 56 | httpclient 57 | 58 | 59 | io.jsonwebtoken 60 | jjwt 61 | 0.7.0 62 | 63 | 64 | 65 | 66 | 67 | 68 | org.springframework.boot 69 | spring-boot-maven-plugin 70 | 1.3.3.RELEASE 71 | 72 | com.imooc.DemoApplication 73 | 74 | 75 | 76 | 77 | repackage 78 | 79 | 80 | 81 | 82 | 83 | demo 84 | 85 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.imooc; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.web.servlet.View; 7 | 8 | import com.imooc.security.core.social.view.ImoocConnecStatusView; 9 | import com.imooc.social.qq.DemoConnectedView; 10 | 11 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 12 | 13 | @SpringBootApplication 14 | @EnableSwagger2 15 | public class DemoApplication { 16 | public static void main(String[] args) { 17 | SpringApplication.run(DemoApplication.class, args); 18 | } 19 | 20 | // 覆盖core包中配置的Bean 21 | @Bean(name = {"connect/qqConnect", "connect/qqConnected"}) 22 | public View qqConnectedView() { 23 | return new DemoConnectedView(); 24 | } 25 | 26 | // 覆盖core包中配置的Bean 27 | @Bean("connect/status") 28 | public View connectStatusView() { 29 | return new ImoocConnecStatusView(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/authentication/DemoAuthenticationFailureHandler.java: -------------------------------------------------------------------------------- 1 | package com.imooc.authentication; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.ServletException; 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.http.HttpStatus; 13 | import org.springframework.security.core.AuthenticationException; 14 | import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; 15 | import org.springframework.stereotype.Component; 16 | 17 | import com.fasterxml.jackson.databind.ObjectMapper; 18 | import com.imooc.security.core.properties.SecurityProperties; 19 | import com.imooc.security.core.properties.contsant.AuthenticationResponseTypeEnum; 20 | import com.imooc.security.core.support.SimpleResponse; 21 | 22 | /** 23 | * 登陆失败处理器demo 24 | * @author Administrator 25 | * 26 | */ 27 | //@Component 28 | public class DemoAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { 29 | 30 | private Logger logger = LoggerFactory.getLogger(getClass()); 31 | 32 | /** 33 | * spring启动的时候会自动注册 34 | */ 35 | @Autowired 36 | private ObjectMapper objectMapper; 37 | 38 | @Autowired 39 | private SecurityProperties securityProperties; 40 | 41 | @Override 42 | public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, 43 | AuthenticationException exception) throws IOException, ServletException { 44 | 45 | logger.info("demo登陆失败"); 46 | 47 | if (AuthenticationResponseTypeEnum.JSON.equals(securityProperties.getBrowser().getAuthentionResponseType())) { 48 | response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); 49 | response.setContentType("application/json;charset=UTF-8"); 50 | response.getWriter().write(objectMapper.writeValueAsString(new SimpleResponse(exception.getMessage()))); 51 | } else if (AuthenticationResponseTypeEnum.DIRECT.equals(securityProperties.getBrowser().getAuthentionResponseType())) { 52 | logger.error(exception.getMessage()); 53 | super.onAuthenticationFailure(request, response, exception); 54 | } 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/authentication/DemoAuthenticationSuccessHandler.java: -------------------------------------------------------------------------------- 1 | package com.imooc.authentication; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.ServletException; 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.security.core.Authentication; 13 | import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; 14 | import org.springframework.stereotype.Component; 15 | 16 | import com.fasterxml.jackson.databind.ObjectMapper; 17 | import com.imooc.security.core.properties.SecurityProperties; 18 | import com.imooc.security.core.properties.contsant.AuthenticationResponseTypeEnum; 19 | 20 | /** 21 | * 登陆成功处理器demo 22 | * @author Administrator 23 | * 24 | */ 25 | //@Component 26 | public class DemoAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler { 27 | 28 | private Logger logger = LoggerFactory.getLogger(getClass()); 29 | 30 | /** 31 | * spring启动的时候会自动注册 32 | */ 33 | @Autowired 34 | private ObjectMapper objectMapper; 35 | 36 | @Autowired 37 | private SecurityProperties securityProperties; 38 | 39 | /** 40 | * Authentication是spring security的核心接口,封装了认证信息 41 | */ 42 | @Override 43 | public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, 44 | Authentication authentication) throws IOException, ServletException { 45 | 46 | logger.info("demo登陆成功"); 47 | 48 | if (AuthenticationResponseTypeEnum.JSON.equals(securityProperties.getBrowser().getAuthentionResponseType())) { 49 | response.setContentType("application/json;charset=UTF-8"); 50 | response.getWriter().write(objectMapper.writeValueAsString(authentication)); 51 | } else if (AuthenticationResponseTypeEnum.DIRECT.equals(securityProperties.getBrowser().getAuthentionResponseType())) { 52 | // 跳转 53 | super.onAuthenticationSuccess(request, response, authentication); 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/authorize/DemoAuthroizeConfigProvider.java: -------------------------------------------------------------------------------- 1 | package com.imooc.authorize; 2 | 3 | import org.springframework.core.annotation.Order; 4 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 5 | import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; 6 | import org.springframework.stereotype.Component; 7 | 8 | import com.imooc.security.core.authorize.AuthorizeConfigProvider; 9 | 10 | @Component 11 | @Order(Integer.MAX_VALUE) 12 | public class DemoAuthroizeConfigProvider implements AuthorizeConfigProvider { 13 | 14 | @Override 15 | public void config(ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry config) { 16 | // anyRequest()需要最后调用,不然后面的配置会失效 17 | config.anyRequest().access("@rbacService.hasPermission(request, authentication)"); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/dto/FileInfo.java: -------------------------------------------------------------------------------- 1 | package com.imooc.dto; 2 | 3 | public class FileInfo { 4 | private String path; 5 | 6 | public FileInfo(String path) { 7 | this.path = path; 8 | } 9 | 10 | public String getPath() { 11 | return path; 12 | } 13 | 14 | public void setPath(String path) { 15 | this.path = path; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/dto/User.java: -------------------------------------------------------------------------------- 1 | package com.imooc.dto; 2 | 3 | import java.util.Date; 4 | 5 | import javax.validation.constraints.Past; 6 | 7 | import org.hibernate.validator.constraints.NotBlank; 8 | 9 | import com.fasterxml.jackson.annotation.JsonView; 10 | import com.imooc.validator.MyConstraint; 11 | 12 | public class User { 13 | public interface UserSimpleView{}; 14 | public interface UserDetailView extends UserSimpleView{}; 15 | 16 | private String id; 17 | @MyConstraint(message = "这是一个测试") 18 | private String username; 19 | @NotBlank(message = "密码不能为空") 20 | private String password; 21 | @Past(message = "生日必须是过去的时间") 22 | private Date birthday; 23 | 24 | @JsonView(UserSimpleView.class) 25 | public String getUsername() { 26 | return username; 27 | } 28 | public void setUsername(String username) { 29 | this.username = username; 30 | } 31 | @JsonView(UserDetailView.class) 32 | public String getPassword() { 33 | return password; 34 | } 35 | public void setPassword(String password) { 36 | this.password = password; 37 | } 38 | @JsonView(UserSimpleView.class) 39 | public String getId() { 40 | return id; 41 | } 42 | public void setId(String id) { 43 | this.id = id; 44 | } 45 | @JsonView(UserSimpleView.class) 46 | public Date getBirthday() { 47 | return birthday; 48 | } 49 | public void setBirthday(Date birthday) { 50 | this.birthday = birthday; 51 | } 52 | @Override 53 | public String toString() { 54 | return "User [id=" + id + ", username=" + username + ", password=" + password + "]"; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/dto/UserQueryCondition.java: -------------------------------------------------------------------------------- 1 | package com.imooc.dto; 2 | 3 | import io.swagger.annotations.ApiModelProperty; 4 | 5 | public class UserQueryCondition { 6 | private String username; 7 | @ApiModelProperty(value = "用户年龄起始值") 8 | private int age; 9 | @ApiModelProperty(value = "用户年龄终止值") 10 | private int ageTo; 11 | private String xxx; 12 | public String getUsername() { 13 | return username; 14 | } 15 | public void setUsername(String username) { 16 | this.username = username; 17 | } 18 | public int getAge() { 19 | return age; 20 | } 21 | public void setAge(int age) { 22 | this.age = age; 23 | } 24 | public int getAgeTo() { 25 | return ageTo; 26 | } 27 | public void setAgeTo(int ageTo) { 28 | this.ageTo = ageTo; 29 | } 30 | public String getXxx() { 31 | return xxx; 32 | } 33 | public void setXxx(String xxx) { 34 | this.xxx = xxx; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/exception/UserNotExistException.java: -------------------------------------------------------------------------------- 1 | package com.imooc.exception; 2 | 3 | public class UserNotExistException extends RuntimeException { 4 | 5 | /** 6 | * 7 | */ 8 | private static final long serialVersionUID = 1L; 9 | 10 | private String id; 11 | 12 | public UserNotExistException (String id) { 13 | super("user not exist"); 14 | this.id = id; 15 | } 16 | 17 | public String getId() { 18 | return id; 19 | } 20 | 21 | public void setId(String id) { 22 | this.id = id; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/security/DemoConnectionSignUp.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security; 2 | 3 | import org.springframework.social.connect.Connection; 4 | import org.springframework.social.connect.ConnectionSignUp; 5 | import org.springframework.stereotype.Component; 6 | 7 | //@Component 8 | public class DemoConnectionSignUp implements ConnectionSignUp { 9 | 10 | @Override 11 | public String execute(Connection connection) { 12 | // 根据社交用户信息默认创建用户并返回用户业务唯一标识 13 | return connection.getDisplayName(); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/security/MyUserDetailsService.java: -------------------------------------------------------------------------------- 1 | package com.imooc.security; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.security.core.authority.AuthorityUtils; 7 | import org.springframework.security.core.userdetails.UserDetailsService; 8 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 9 | import org.springframework.security.crypto.password.PasswordEncoder; 10 | import org.springframework.social.security.SocialUser; 11 | import org.springframework.social.security.SocialUserDetails; 12 | import org.springframework.social.security.SocialUserDetailsService; 13 | import org.springframework.stereotype.Component; 14 | 15 | @Component 16 | public class MyUserDetailsService implements UserDetailsService, SocialUserDetailsService { 17 | 18 | private Logger logger = LoggerFactory.getLogger(getClass()); 19 | 20 | @Autowired 21 | private PasswordEncoder passwordEncoder; 22 | 23 | @Override 24 | public SocialUserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 25 | String password = "123456"; 26 | logger.info("登陆用户名:" + username + "登陆成功"); 27 | return new SocialUser(username, passwordEncoder.encode(password), true, true, true, true, AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN,ROLE_USER")); 28 | } 29 | 30 | @Override 31 | public SocialUserDetails loadUserByUserId(String userId) throws UsernameNotFoundException { 32 | String password = "123456"; 33 | logger.info("登陆用户ID:" + userId + "登陆成功"); 34 | return new SocialUser(userId, passwordEncoder.encode(password), true, true, true, true, AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN")); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/service/HelloService.java: -------------------------------------------------------------------------------- 1 | package com.imooc.service; 2 | 3 | public interface HelloService { 4 | String greeting(String name); 5 | } 6 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/service/impl/HelloServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.imooc.service.impl; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | import com.imooc.service.HelloService; 6 | 7 | @Service 8 | public class HelloServiceImpl implements HelloService { 9 | 10 | @Override 11 | public String greeting(String name) { 12 | return "hello " + name; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/social/qq/DemoConnectedView.java: -------------------------------------------------------------------------------- 1 | package com.imooc.social.qq; 2 | 3 | import java.util.Map; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | 8 | import org.springframework.web.servlet.view.AbstractView; 9 | 10 | public class DemoConnectedView extends AbstractView { 11 | 12 | @Override 13 | protected void renderMergedOutputModel(Map model, HttpServletRequest request, 14 | HttpServletResponse response) throws Exception { 15 | response.setContentType("text/plain;charset=UTF-8"); 16 | if (model.get("connections") == null) { 17 | response.getWriter().write("demo 解绑成功"); 18 | } else { 19 | response.getWriter().write("demo 绑定成功"); 20 | } 21 | 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/social/qq/DemoStatusView.java: -------------------------------------------------------------------------------- 1 | package com.imooc.social.qq; 2 | 3 | import java.util.HashMap; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.servlet.http.HttpServletResponse; 9 | 10 | import org.apache.commons.collections.CollectionUtils; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.social.connect.Connection; 13 | import org.springframework.web.servlet.view.AbstractView; 14 | 15 | import com.fasterxml.jackson.databind.ObjectMapper; 16 | 17 | public class DemoStatusView extends AbstractView { 18 | 19 | @Autowired 20 | private ObjectMapper objectMapper; 21 | 22 | @Override 23 | protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) 24 | throws Exception { 25 | 26 | @SuppressWarnings("unchecked") 27 | Map>> connections = (Map>>) model.get("connectionMap"); 28 | 29 | Map result = new HashMap<>(); 30 | for (String key : connections.keySet()) { 31 | result.put(key, CollectionUtils.isNotEmpty(connections.get(key))); 32 | } 33 | 34 | response.setContentType("application/json;charset=UTF=8"); 35 | response.getWriter().write(objectMapper.writeValueAsString(result)); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/validator/MyConstraint.java: -------------------------------------------------------------------------------- 1 | package com.imooc.validator; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | import javax.validation.Constraint; 9 | import javax.validation.Payload; 10 | 11 | @Target({ElementType.METHOD, ElementType.FIELD}) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Constraint(validatedBy = MyConstraintValidator.class) 14 | public @interface MyConstraint { 15 | String message(); 16 | Class[] groups() default { }; 17 | Class[] payload() default { }; 18 | } 19 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/validator/MyConstraintValidator.java: -------------------------------------------------------------------------------- 1 | package com.imooc.validator; 2 | 3 | import javax.validation.ConstraintValidator; 4 | import javax.validation.ConstraintValidatorContext; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | 10 | import com.imooc.service.HelloService; 11 | 12 | public class MyConstraintValidator implements ConstraintValidator { 13 | 14 | private Logger logger = LoggerFactory.getLogger(getClass()); 15 | 16 | @Autowired 17 | private HelloService helloService; 18 | 19 | @Override 20 | public void initialize(MyConstraint anno) { 21 | logger.info("my validator init"); 22 | } 23 | 24 | @Override 25 | public boolean isValid(Object value, ConstraintValidatorContext arg1) { 26 | logger.info(helloService.greeting("tom")); 27 | logger.info(value.toString()); 28 | return false; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/web/aspect/TimeAspect.java: -------------------------------------------------------------------------------- 1 | package com.imooc.web.aspect; 2 | 3 | import org.aspectj.lang.ProceedingJoinPoint; 4 | import org.aspectj.lang.annotation.Around; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | // 切入点, 在哪些地方起作用, 在什么时候起作用 9 | // 增强, 执行的额外逻辑方法 10 | //@Aspect 11 | //@Component 12 | public class TimeAspect { 13 | 14 | private Logger logger = LoggerFactory.getLogger(getClass()); 15 | 16 | @Around("execution(* com.imooc.web.controller.UserController.*(..))") 17 | public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable { 18 | logger.info("time aspect start..."); 19 | 20 | Object[] args = pjp.getArgs(); 21 | for (Object arg : args) { 22 | logger.info("time aspect arg is:" + arg); 23 | } 24 | 25 | long aspectStartTime = System.currentTimeMillis(); 26 | Object result = pjp.proceed(); 27 | logger.info("time aspect controller result: " + result); 28 | logger.info("time aspect controller 耗时: " + (System.currentTimeMillis() - aspectStartTime)); 29 | 30 | logger.info("time aspect end.."); 31 | return result; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/web/async/AsyncController.java: -------------------------------------------------------------------------------- 1 | package com.imooc.web.async; 2 | 3 | import java.util.concurrent.Callable; 4 | 5 | import org.apache.commons.lang3.RandomStringUtils; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | import org.springframework.web.context.request.async.DeferredResult; 13 | 14 | @RestController 15 | @RequestMapping("/orders") 16 | public class AsyncController { 17 | 18 | private Logger logger = LoggerFactory.getLogger(getClass()); 19 | @Autowired 20 | private MockQueue queue; 21 | @Autowired 22 | private DeferredResultHolder deferredResultHolder; 23 | 24 | @GetMapping 25 | public DeferredResult order() { 26 | logger.info("主线程开始..."); 27 | 28 | String placeOrder = RandomStringUtils.randomNumeric(6); 29 | 30 | // 同步 31 | // String result = placeOrder; 32 | // try { 33 | // Thread.sleep(2000L); 34 | // } catch (InterruptedException e) { 35 | // e.printStackTrace(); 36 | // } 37 | 38 | // 异步1: Callable形式 39 | // Callable result = new Callable() { 40 | // @Override 41 | // public String call() throws Exception { 42 | // logger.info("副线程开始..."); 43 | // Thread.sleep(2000L); 44 | // logger.info("副线程结束..."); 45 | // return "place order success:" + placeOrder; 46 | // } 47 | // }; 48 | 49 | // 异步2:DeferredResult形式 50 | queue.setPlaceOrder(placeOrder); 51 | DeferredResult result = new DeferredResult<>(); 52 | deferredResultHolder.getMap().put(placeOrder, result); 53 | logger.info("主线程开启线程来异步处理下单..."); 54 | 55 | logger.info("主线程结束..."); 56 | return result; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/web/async/DeferredResultHolder.java: -------------------------------------------------------------------------------- 1 | package com.imooc.web.async; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.web.context.request.async.DeferredResult; 8 | 9 | @Component 10 | public class DeferredResultHolder { 11 | private Map> map = new HashMap<>(); 12 | 13 | public Map> getMap() { 14 | return map; 15 | } 16 | 17 | public void setMap(Map> map) { 18 | this.map = map; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/web/async/MockQueue.java: -------------------------------------------------------------------------------- 1 | package com.imooc.web.async; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | public class MockQueue { 9 | 10 | private Logger logger = LoggerFactory.getLogger(getClass()); 11 | private String placeOrder; 12 | private String completeOrder; 13 | public String getPlaceOrder() { 14 | return placeOrder; 15 | } 16 | public void setPlaceOrder(String placeOrder) { 17 | new Thread(() -> { 18 | this.placeOrder = placeOrder; 19 | logger.info("调用方正在发送消息通知订单服务处理,订单号:" + placeOrder ); 20 | try { 21 | Thread.sleep(2000L); 22 | } catch (InterruptedException e) { 23 | e.printStackTrace(); 24 | } 25 | this.completeOrder = placeOrder; 26 | logger.info("调用方接收到订单服务的处理成功的结果,订单号:" + placeOrder); 27 | }).start(); 28 | } 29 | public String getCompleteOrder() { 30 | return completeOrder; 31 | } 32 | public void setCompleteOrder(String completeOrder) { 33 | this.completeOrder = completeOrder; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/web/async/QueueListener.java: -------------------------------------------------------------------------------- 1 | package com.imooc.web.async; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.context.ApplicationListener; 8 | import org.springframework.context.event.ContextRefreshedEvent; 9 | import org.springframework.stereotype.Component; 10 | 11 | @Component 12 | public class QueueListener implements ApplicationListener { 13 | 14 | private Logger logger = LoggerFactory.getLogger(getClass()); 15 | 16 | @Autowired 17 | private MockQueue queue; 18 | 19 | @Autowired 20 | private DeferredResultHolder deferredResultHolder; 21 | 22 | @Override 23 | public void onApplicationEvent(ContextRefreshedEvent event) { 24 | new Thread(() -> { 25 | while (true) { 26 | if (StringUtils.isNotBlank(queue.getCompleteOrder())) { 27 | String completeOrder = queue.getCompleteOrder(); 28 | 29 | logger.info("监听到调用方已成功接收订单服务的处理结果,正在通知客户端显示,订单号:" + completeOrder); 30 | deferredResultHolder.getMap().get(completeOrder).setResult("place order success:" + completeOrder); 31 | 32 | queue.setCompleteOrder(null); 33 | } else { 34 | try { 35 | Thread.sleep(100L); 36 | } catch (InterruptedException e) { 37 | e.printStackTrace(); 38 | } 39 | } 40 | } 41 | }).start(); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/web/config/WebConfig.java: -------------------------------------------------------------------------------- 1 | package com.imooc.web.config; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer; 11 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 12 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 13 | 14 | import com.imooc.web.filter.TimeFilter; 15 | import com.imooc.web.interceptor.TimeInterceptor; 16 | 17 | @Configuration 18 | public class WebConfig extends WebMvcConfigurerAdapter { 19 | 20 | // @Bean 21 | // public FilterRegistrationBean timeFilter() { 22 | // FilterRegistrationBean registrationBean = new FilterRegistrationBean(); 23 | // 24 | // TimeFilter timeFilter = new TimeFilter(); 25 | // registrationBean.setFilter(timeFilter); 26 | // 27 | // List urls = new ArrayList<>(); 28 | // urls.add("/*"); 29 | // registrationBean.setUrlPatterns(urls); 30 | // 31 | // return registrationBean; 32 | // } 33 | 34 | // @Autowired 35 | // private TimeInterceptor timeInterceptor; 36 | // @Override 37 | // public void addInterceptors(InterceptorRegistry registry) { 38 | // super.addInterceptors(registry); 39 | // registry.addInterceptor(timeInterceptor); 40 | // } 41 | 42 | // @Override 43 | // public void configureAsyncSupport(AsyncSupportConfigurer configurer) { 44 | // configurer.registerCallableInterceptors(interceptors); // 设置Callable形式的拦截器 45 | // configurer.registerDeferredResultInterceptors(interceptors); // 设置DeferredResult形式的拦截器 46 | // configurer.setDefaultTimeout(timeout); // 设置处理线程的默认超时时间 47 | // configurer.setTaskExecutor(taskExecutor); // 设置处理线程的线程池 48 | // } 49 | } 50 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/web/controller/ControllerExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.imooc.web.controller; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.web.bind.annotation.ControllerAdvice; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | import org.springframework.web.bind.annotation.ResponseBody; 10 | import org.springframework.web.bind.annotation.ResponseStatus; 11 | 12 | import com.imooc.exception.UserNotExistException; 13 | 14 | @ControllerAdvice 15 | public class ControllerExceptionHandler { 16 | @ExceptionHandler(UserNotExistException.class) 17 | @ResponseBody 18 | @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) 19 | public Map handleUserNotExistException(UserNotExistException ex) { 20 | Map result = new HashMap<>(); 21 | result.put("id", ex.getId()); 22 | result.put("message", ex.getMessage()); 23 | return result; 24 | } 25 | 26 | @ExceptionHandler(Exception.class) 27 | @ResponseBody 28 | @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) 29 | public Map authenticationException(Exception ex) { 30 | Map result = new HashMap<>(); 31 | result.put("message", ex.getMessage()); 32 | return result; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/web/controller/FileController.java: -------------------------------------------------------------------------------- 1 | package com.imooc.web.controller; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.InputStream; 6 | import java.io.OutputStream; 7 | 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | 11 | import org.apache.commons.io.IOUtils; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | import org.springframework.web.bind.annotation.GetMapping; 15 | import org.springframework.web.bind.annotation.PathVariable; 16 | import org.springframework.web.bind.annotation.PostMapping; 17 | import org.springframework.web.bind.annotation.RequestMapping; 18 | import org.springframework.web.bind.annotation.RestController; 19 | import org.springframework.web.multipart.MultipartFile; 20 | 21 | import com.imooc.dto.FileInfo; 22 | 23 | @RestController 24 | @RequestMapping("/files") 25 | public class FileController { 26 | 27 | private Logger logger = LoggerFactory.getLogger(getClass()); 28 | 29 | private String folder = "C:/"; 30 | 31 | @PostMapping 32 | public FileInfo upload(MultipartFile file) throws Exception { 33 | logger.info(file.getName()); //参数名 34 | logger.info(file.getOriginalFilename()); //原始文件名 35 | logger.info(file.getSize() + ""); //文件尺寸 36 | 37 | File localFile = new File(folder, System.currentTimeMillis() + ".txt"); 38 | file.transferTo(localFile); 39 | 40 | return new FileInfo(localFile.getAbsolutePath()); 41 | } 42 | 43 | @GetMapping("/{id}") 44 | public void download(@PathVariable String id, HttpServletRequest request, HttpServletResponse response) throws Exception { 45 | try (InputStream inputStream = new FileInputStream(new File(folder, id + ".txt")); 46 | OutputStream outputStream = response.getOutputStream();) { 47 | response.setContentType("application/x-download"); 48 | response.addHeader("Content-Disposition", "attachment;filename=test.txt"); 49 | IOUtils.copy(inputStream, outputStream); 50 | } catch (Exception e) { 51 | throw e; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/web/filter/TimeFilter.java: -------------------------------------------------------------------------------- 1 | package com.imooc.web.filter; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.Filter; 6 | import javax.servlet.FilterChain; 7 | import javax.servlet.FilterConfig; 8 | import javax.servlet.ServletException; 9 | import javax.servlet.ServletRequest; 10 | import javax.servlet.ServletResponse; 11 | import javax.servlet.http.HttpServletRequest; 12 | 13 | // 使用注解@Component也能把filter注入到web环境, 也可以通过创建FilterRegistratorBean注入 14 | //@Component 15 | public class TimeFilter implements Filter { 16 | 17 | @Override 18 | public void destroy() { 19 | System.out.println("time filter destory"); 20 | } 21 | 22 | @Override 23 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 24 | throws IOException, ServletException { 25 | System.out.println("time filter start..."); 26 | System.out.println("time filter request url" + ((HttpServletRequest)request).getRequestURL()); 27 | long filterStartTime = System.currentTimeMillis(); 28 | chain.doFilter(request, response); 29 | System.out.println("time filter 耗时:" + (System.currentTimeMillis() - filterStartTime)); 30 | System.out.println("time filter end..."); 31 | } 32 | 33 | @Override 34 | public void init(FilterConfig config) throws ServletException { 35 | System.out.println("time filter init"); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/web/interceptor/TimeInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.imooc.web.interceptor; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import javax.servlet.http.HttpServletResponse; 5 | 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.web.method.HandlerMethod; 8 | import org.springframework.web.servlet.HandlerInterceptor; 9 | import org.springframework.web.servlet.ModelAndView; 10 | 11 | @Component 12 | public class TimeInterceptor implements HandlerInterceptor { 13 | 14 | // 无论controller是抛出异常还是正常执行完毕, 该方法都会执行 15 | // 但是如果@ControllerAdvice把异常处理掉了, 则afterCompletion则不会接收到异常 16 | @Override 17 | public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) 18 | throws Exception { 19 | System.out.println("time interceptor afterCompletion start..."); 20 | System.out.println("time interceptor afterCompletion 耗时: " + (System.currentTimeMillis() - (Long)request.getAttribute("interceptorStartTime"))); 21 | System.out.println("time interceptor afterCompletion ex: " + ex); 22 | System.out.println("time interceptor afterCompletion end..."); 23 | } 24 | 25 | // controller抛出异常则该方法不会被执行 26 | @Override 27 | public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv) 28 | throws Exception { 29 | System.out.println("time interceptor postHandle start..."); 30 | System.out.println("time interceptor postHandle 耗时: " + (System.currentTimeMillis() - (Long)request.getAttribute("interceptorStartTime"))); 31 | System.out.println("time interceptor postHandle end..."); 32 | } 33 | 34 | @Override 35 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 36 | System.out.println("time interceptor preHandle start..."); 37 | System.out.println("time interceptor preHandle handleClass: " + ((HandlerMethod)handler).getBean().getClass().getName()); 38 | System.out.println("time interceptor preHandle handleMethod: " + ((HandlerMethod)handler).getMethod().getName()); 39 | request.setAttribute("interceptorStartTime", System.currentTimeMillis()); 40 | System.out.println("time interceptor preHandle end..."); 41 | return true; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/java/com/imooc/wiremock/MockServer.java: -------------------------------------------------------------------------------- 1 | package com.imooc.wiremock; 2 | 3 | import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; 4 | import static com.github.tomakehurst.wiremock.client.WireMock.configureFor; 5 | import static com.github.tomakehurst.wiremock.client.WireMock.get; 6 | import static com.github.tomakehurst.wiremock.client.WireMock.removeAllMappings; 7 | import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; 8 | import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; 9 | 10 | public class MockServer { 11 | 12 | public static void main(String[] args) { 13 | configureFor(8081); 14 | removeAllMappings(); 15 | 16 | stubFor(get(urlPathEqualTo("/order/1")) 17 | .willReturn(aResponse() 18 | .withBody("{\"id\":111}") 19 | .withStatus(200))); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #jdbc 2 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 3 | spring.datasource.url=jdbc:mysql://127.0.0.1:3306/imooc-security-demo?useUnicode=yes&characterEncoding=utf-8 4 | spring.datasource.username=root 5 | spring.datasource.password=123456 6 | 7 | # server 8 | server.port=8080 9 | # 单位: 秒 10 | server.session.timeout=3600 11 | 12 | # spring session 13 | spring.session.store-type=none 14 | 15 | # security 16 | # 是否启用浏览器的basic认证,默认true 17 | # 帐号为user,密码为服务启动时控制台打印出来。 18 | #security.basic.enabled=false 19 | 20 | # custome security browser 21 | imooc.security.browser.sign-up-page-url=/demo-signup.html 22 | imooc.security.browser.sign-up-process-url=/user/regist 23 | imooc.security.browser.un-authentication-url=/authentication/dispatch 24 | imooc.security.browser.login-page-url=/demo-signin.html 25 | imooc.security.browser.validate-code-url-image=/code/image 26 | imooc.security.browser.validate-code-url-sms=/code/sms 27 | imooc.security.browser.login-process-url-form=/authentication/form 28 | imooc.security.browser.login-process-url-mobile=/authentication/mobile 29 | imooc.security.browser.authention-response-type=DIRECT 30 | 31 | # custom security browser session 32 | imooc.security.browser.session.max-sessions-prevents-login=false 33 | imooc.security.browser.session.maxinum-session=1 34 | imooc.security.browser.session.session-invalid-redirect-url=/session/invalid 35 | 36 | # custom security image code 37 | imooc.security.code.image.length=4 38 | imooc.security.code.image.width=120 39 | imooc.security.code.image.height=60 40 | imooc.security.code.image.fontSize=40 41 | imooc.security.code.image.url=/users 42 | imooc.security.code.image.expire-in=60 43 | 44 | # custom security sms code 45 | imooc.security.code.sms.length=6 46 | imooc.security.code.sms.expire-in=60 47 | imooc.security.code.sms.url=/files 48 | 49 | # custom security social 50 | imooc.security.social.filter-process-url=/login 51 | 52 | # custom security qq social 53 | imooc.security.social.qq.app-id=101386962 54 | imooc.security.social.qq.app-secret=2a0f820407df400b84a854d054be8b6a 55 | imooc.security.social.qq.provider-id=qq 56 | 57 | # custom security weixin social 58 | imooc.security.social.weixin.app-id=1 59 | imooc.security.social.weixin.app-secret=1 60 | imooc.security.social.weixin.provider-id=weixin 61 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/resources/resources/demo-banding.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | demo 绑定 6 | 7 | 8 | 9 |

这是标准的绑定页面, 这里以qq为例

10 |
11 | 12 |
13 |
14 |

解绑QQ的话需要发送/connect/{providerId}的delete请求

15 | 16 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/resources/resources/demo-signin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | imooc 登录 6 | 7 | 8 | 9 | 10 |

用户名登录

11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 27 | 28 | 29 | 记住我 30 | 31 | 32 | 33 | 34 |
用户名:
密码:
图形验证码: 24 | 25 | 26 |
35 |
36 | 37 |
38 | 39 |

手机登录

40 |
41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 52 | 53 | 54 | 55 | 56 |
手机号:
图形验证码: 49 | 50 | 发送验证码 51 |
57 |
58 | 59 |

社交登陆

60 | QQ登陆 61 | 62 | 73 | 74 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/resources/resources/demo-signout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 退出登陆 6 | 7 | 8 |

demo 退出登陆成功

9 | 10 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/resources/resources/demo-signup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | demo 注册 6 | 7 | 8 | 9 | 10 |

用户名登录

11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 |
用户名:
密码:
23 | 24 | 25 |
28 |
29 | 30 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/resources/resources/error/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 404 6 | 7 | 8 | 404 9 | 10 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/resources/resources/error/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 500 6 | 7 | 8 | 500 9 | 10 | -------------------------------------------------------------------------------- /imooc-security-demo/src/main/resources/resources/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | demo 首页 6 | 7 | 8 | xxx, 欢迎您 9 |
10 | 退出 11 | 12 | -------------------------------------------------------------------------------- /imooc-security-demo/src/test/java/com/imooc/web/controller/FileControllerTest.java: -------------------------------------------------------------------------------- 1 | package com.imooc.web.controller; 2 | 3 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.fileUpload; 4 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 5 | 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | import org.springframework.mock.web.MockMultipartFile; 12 | import org.springframework.test.context.junit4.SpringRunner; 13 | import org.springframework.test.web.servlet.MockMvc; 14 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 15 | import org.springframework.web.context.WebApplicationContext; 16 | 17 | @RunWith(SpringRunner.class) 18 | @SpringBootTest 19 | public class FileControllerTest { 20 | @Autowired 21 | private WebApplicationContext wac; 22 | 23 | private MockMvc mockMvc; 24 | 25 | @Before 26 | public void step() { 27 | mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); 28 | } 29 | 30 | @Test 31 | public void whenUploadSuccess() throws Exception { 32 | String result = mockMvc.perform(fileUpload("/files") 33 | .file(new MockMultipartFile("file", "test.txt", "multipart/form-data", "hello upload".getBytes("UTF-8")))) 34 | .andExpect(status().isOk()) 35 | .andReturn().getResponse().getContentAsString(); 36 | System.out.println(result); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /imooc-security-demo/src/test/java/com/imooc/web/controller/UserControllerTest.java: -------------------------------------------------------------------------------- 1 | package com.imooc.web.controller; 2 | 3 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; 4 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 5 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; 6 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; 7 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; 8 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 9 | 10 | import java.util.Date; 11 | 12 | import org.junit.Before; 13 | import org.junit.Test; 14 | import org.junit.runner.RunWith; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.boot.test.context.SpringBootTest; 17 | import org.springframework.http.MediaType; 18 | import org.springframework.test.context.junit4.SpringRunner; 19 | import org.springframework.test.web.servlet.MockMvc; 20 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 21 | import org.springframework.web.context.WebApplicationContext; 22 | 23 | @RunWith(SpringRunner.class) //用SpringRunner来跑测试用例 24 | @SpringBootTest //整个类是测试用例 25 | public class UserControllerTest { 26 | @Autowired 27 | private WebApplicationContext wac; 28 | 29 | private MockMvc mockMvc; 30 | 31 | @Before 32 | public void setup() { 33 | mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); 34 | } 35 | 36 | @Test 37 | public void whenQuerySuccess() throws Exception { 38 | String result = mockMvc.perform(get("/users") 39 | // UserQueryCondition对象参数 40 | .param("username", "jojo") 41 | .param("age", "18") 42 | .param("ageTo", "60") 43 | .param("xxx", "yyy") 44 | // Pageable对象参数 45 | .param("size", "15") 46 | .param("page", "3") 47 | .param("sort", "age,desc") 48 | // 请求的content-type 49 | .contentType(MediaType.APPLICATION_JSON_UTF8)) 50 | // 期望返回200状态码 51 | .andExpect(status().isOk()) 52 | // 期望返回的json数组的长度为3 53 | // JsonPath地址:https://github.com/json-path/JsonPath 54 | .andExpect(jsonPath("$.length()").value(3)) 55 | .andReturn().getResponse().getContentAsString(); 56 | System.out.println(result); 57 | } 58 | 59 | @Test 60 | public void whenGetInfoSuccess() throws Exception { 61 | String result = mockMvc.perform(get("/users/1") 62 | .contentType(MediaType.APPLICATION_JSON_UTF8)) 63 | .andExpect(status().isOk()) 64 | .andExpect(jsonPath("$.username").value("tom")) 65 | .andReturn().getResponse().getContentAsString(); 66 | System.out.println(result); 67 | } 68 | 69 | @Test 70 | public void whenGetInfoFail() throws Exception { 71 | mockMvc.perform(get("/users/a") 72 | .contentType(MediaType.APPLICATION_JSON_UTF8)) 73 | .andExpect(status().is4xxClientError()); 74 | } 75 | 76 | @Test 77 | public void whenCreateSuccess() throws Exception { 78 | Date date = new Date(); 79 | System.out.println("请求date: " + date); 80 | String content = "{\"username\":\"tom\", \"password\":null, \"birthday\": " + date.getTime() + "}"; 81 | System.out.println("请求json: " + content); 82 | String result = mockMvc.perform(post("/users") 83 | .contentType(MediaType.APPLICATION_JSON_UTF8) 84 | .content(content)) 85 | .andExpect(status().isOk()) 86 | .andExpect(jsonPath("$.id").value("1")) 87 | .andReturn().getResponse().getContentAsString(); 88 | System.out.println("返回json: " + result); 89 | } 90 | 91 | @Test 92 | public void whneUpdateSuccess() throws Exception { 93 | Date date = new Date(System.currentTimeMillis() + 1000 * 3600 * 24 * 365); 94 | System.out.println("请求date: " + date); 95 | String content = "{\"id\":\"1\", \"username\":\"tom\", \"password\":null, \"birthday\": " + date.getTime() + "}"; 96 | System.out.println("请求json: " + content); 97 | String result = mockMvc.perform(put("/users/1") 98 | .contentType(MediaType.APPLICATION_JSON_UTF8) 99 | .content(content)) 100 | .andExpect(status().isOk()) 101 | .andExpect(jsonPath("$.id").value("1")) 102 | .andReturn().getResponse().getContentAsString(); 103 | System.out.println("返回json: " + result); 104 | } 105 | 106 | @Test 107 | public void whenDeleteSuccess() throws Exception { 108 | mockMvc.perform(delete("/users/1") 109 | .contentType(MediaType.APPLICATION_JSON_UTF8)) 110 | .andExpect(status().isOk()); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /imooc-security-demo/笔记-demo.txt: -------------------------------------------------------------------------------- 1 | 1. 可用@GetMapping/@PostMapping等 代替 @RequestMapping 2 | 3 | 2. 可配置JsonView来控制实体属性输出 4 | 5 | 3. @RequestMapping里配置的Url参数可使用正则表达式 6 | 7 | 4. 编写代码, 用例先行; 可使用MockMvc编写测试用例。 8 | 当有测试用例的时候, 可用来校验重构代码后业务依然不受影响。 9 | 10 | 5. @RequestBody 可以使请求中的body转为实体参数 11 | 12 | 6. 时间参数的请求和返回, 都使用时间戳来传输 13 | 14 | 7. 使用Hibernate Validator注解对请求参数进行校验, 15 | controller中需要为请求参数添加@Valid注解来激活参数校验功能, 16 | 如需定制参数校验失败的处理, 可在controller的请求参数列表中追加BindingResult参数, 这样子就不会直接返回400, 而是可定制处理 17 | 也可以继承ConstraintValidator来自定义校验注解 18 | 19 | 8. 可在src/main/resources/创建resources/error目录, 创建404.html页面来响应浏览器错误页 20 | 21 | 9. 可通过@ControllerAdvice定义自定义异常 22 | 23 | 10. 通过注册FilterRegistratorBean这个bean来注入过滤器, 过滤器需要实现Filter接口 24 | 注意, 建议通过FilterRegistrationBean来注入filter 25 | 26 | 11. 通过注册InterceptorRegistratorBean这个bean来注入拦截器, 拦截器需要实现HandlerInterceptor接口, 27 | 值得注意的是, 如果Controller抛出的异常被ControllerAdvice处理掉的话, 则Interceptor的afterCompletion方法会接收不到ex参数 28 | 29 | 12. Controller通过MultipartFile参数来接收上传文件 30 | 31 | 13. 异步请求方式有两种, 分别是Callable和DeferredResult 32 | 33 | 14. 使用Swagger去自动生成api文档 34 | 35 | 15. 使用WireMock去伪造Restful服务 36 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.imooc.security 5 | imooc-security 6 | 0.0.1-SNAPSHOT 7 | pom 8 | 9 | 10 | 1.0.0-SNAPSHOT 11 | 12 | 13 | 14 | 15 | 16 | io.spring.platform 17 | platform-bom 18 | Brussels-SR4 19 | pom 20 | import 21 | 22 | 23 | org.springframework.cloud 24 | spring-cloud-dependencies 25 | Dalston.SR2 26 | pom 27 | import 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | org.apache.maven.plugins 36 | maven-compiler-plugin 37 | 2.3.2 38 | 39 | 1.8 40 | 1.8 41 | UTF-8 42 | 43 | 44 | 45 | 46 | 47 | 48 | imooc-security-app 49 | imooc-security-browser 50 | imooc-security-core 51 | imooc-security-demo 52 | imooc-security-authorize 53 | 54 | -------------------------------------------------------------------------------- /spring security核心知识点截图/01、SpringSecurity过滤器链原理.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuquan0769/spring-security-imooc/4c35a1d3544d7f78207fec8c5161f6d8c4a80e01/spring security核心知识点截图/01、SpringSecurity过滤器链原理.JPG -------------------------------------------------------------------------------- /spring security核心知识点截图/02、SpringSecurity认证流程核心类、.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuquan0769/spring-security-imooc/4c35a1d3544d7f78207fec8c5161f6d8c4a80e01/spring security核心知识点截图/02、SpringSecurity认证流程核心类、.JPG -------------------------------------------------------------------------------- /spring security核心知识点截图/03、RememberMe功能流程.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuquan0769/spring-security-imooc/4c35a1d3544d7f78207fec8c5161f6d8c4a80e01/spring security核心知识点截图/03、RememberMe功能流程.JPG -------------------------------------------------------------------------------- /spring security核心知识点截图/04、Oauth所要解决的问题.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuquan0769/spring-security-imooc/4c35a1d3544d7f78207fec8c5161f6d8c4a80e01/spring security核心知识点截图/04、Oauth所要解决的问题.JPG -------------------------------------------------------------------------------- /spring security核心知识点截图/05、Oauth中的角色.和抽象的操作交互流程.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuquan0769/spring-security-imooc/4c35a1d3544d7f78207fec8c5161f6d8c4a80e01/spring security核心知识点截图/05、Oauth中的角色.和抽象的操作交互流程.JPG -------------------------------------------------------------------------------- /spring security核心知识点截图/06、Oauth的四种用户授权模式.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuquan0769/spring-security-imooc/4c35a1d3544d7f78207fec8c5161f6d8c4a80e01/spring security核心知识点截图/06、Oauth的四种用户授权模式.JPG -------------------------------------------------------------------------------- /spring security核心知识点截图/07、Oauth授权码模式流程.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuquan0769/spring-security-imooc/4c35a1d3544d7f78207fec8c5161f6d8c4a80e01/spring security核心知识点截图/07、Oauth授权码模式流程.JPG -------------------------------------------------------------------------------- /spring security核心知识点截图/08、Spring Social模块介绍.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuquan0769/spring-security-imooc/4c35a1d3544d7f78207fec8c5161f6d8c4a80e01/spring security核心知识点截图/08、Spring Social模块介绍.JPG -------------------------------------------------------------------------------- /spring security核心知识点截图/09、Spring Social认认证流程核心类.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuquan0769/spring-security-imooc/4c35a1d3544d7f78207fec8c5161f6d8c4a80e01/spring security核心知识点截图/09、Spring Social认认证流程核心类.JPG -------------------------------------------------------------------------------- /spring security核心知识点截图/10、Spring Security OAuth开发第三方应用认证框架.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuquan0769/spring-security-imooc/4c35a1d3544d7f78207fec8c5161f6d8c4a80e01/spring security核心知识点截图/10、Spring Security OAuth开发第三方应用认证框架.JPG -------------------------------------------------------------------------------- /spring security核心知识点截图/11、Spring Security OAuth2核心源码.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuquan0769/spring-security-imooc/4c35a1d3544d7f78207fec8c5161f6d8c4a80e01/spring security核心知识点截图/11、Spring Security OAuth2核心源码.JPG -------------------------------------------------------------------------------- /spring security核心知识点截图/12、用Spring Security OAuth2重构APP 图片验证码和短信验证码登陆.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuquan0769/spring-security-imooc/4c35a1d3544d7f78207fec8c5161f6d8c4a80e01/spring security核心知识点截图/12、用Spring Security OAuth2重构APP 图片验证码和短信验证码登陆.JPG -------------------------------------------------------------------------------- /spring security核心知识点截图/13、用Spring Security OAuth2 重构APP 社交授权码授权模式登陆.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuquan0769/spring-security-imooc/4c35a1d3544d7f78207fec8c5161f6d8c4a80e01/spring security核心知识点截图/13、用Spring Security OAuth2 重构APP 社交授权码授权模式登陆.JPG -------------------------------------------------------------------------------- /spring security核心知识点截图/13、用Spring Security OAuth2 重构APP 社交简化授权模式登陆.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuquan0769/spring-security-imooc/4c35a1d3544d7f78207fec8c5161f6d8c4a80e01/spring security核心知识点截图/13、用Spring Security OAuth2 重构APP 社交简化授权模式登陆.JPG -------------------------------------------------------------------------------- /spring security核心知识点截图/14、jwt的特点.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuquan0769/spring-security-imooc/4c35a1d3544d7f78207fec8c5161f6d8c4a80e01/spring security核心知识点截图/14、jwt的特点.JPG -------------------------------------------------------------------------------- /spring security核心知识点截图/spring security过滤器一览.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhuquan0769/spring-security-imooc/4c35a1d3544d7f78207fec8c5161f6d8c4a80e01/spring security核心知识点截图/spring security过滤器一览.png --------------------------------------------------------------------------------