2 Star 7 Fork 14

石头 / imooc-security

forked from AJie / imooc-security 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

###Spring Security过滤器链 ![Spring Security基本原理](images/Spring Security基本原理.JPG)

###Spring Security认证流程 ![](images/Spring Security认证流程.JPG)

###Spring Security记住我原理 ![](images/Spring Security记住我流程.JPG)

记住我过滤器的位置

###自定义验证码接口重构流程

###自定义的短信验证码过滤器流程 单独自定义短信验证码过滤器是为了其他模块可以重用而不仅仅是登录的时候才能用

###Spring Security配置重构图 ![](images/Spring Security配置重构.JPG)

###OAuth2协议授权码模式原理

###使用Spring Social完成社交登录 ![](images/Spring Social原理.JPG)

![](images/Spring Social过滤器位置.JPG)

###Spring Social简述图 ![](images/Spring Social简述图.JPG)

###Spring Social运行流程(橘色部分为自定义组件) ![](images/Spring Social流程.JPG)

####SocialAuthenticationFilter调用attemptAuthService()方法调用OAuth2AuthenticationService的getAuthToken方法 #####OAuth2AuthenticationService

public SocialAuthenticationToken getAuthToken(HttpServletRequest request, HttpServletResponse response) throws SocialAuthenticationRedirectException {
		String code = request.getParameter("code");
		if (!StringUtils.hasText(code)) {//参数中没有code
			OAuth2Parameters params =  new OAuth2Parameters();
			params.setRedirectUri(buildReturnToUrl(request));
			setScope(request, params);
			params.add("state", generateState(connectionFactory, request));
			addCustomParameters(params);
			//没有传入code,抛出重定向异常重定向到QQ的授权网址上去
			throw new SocialAuthenticationRedirectException(getConnectionFactory().getOAuthOperations().buildAuthenticateUrl(params));
		} else if (StringUtils.hasText(code)) {//请求参数中有code
			try {
				String returnToUrl = buildReturnToUrl(request);
				//拿到ConnectionFactory(QQConnectionFactory)和OAuthOperations(QQOAthTemplate)去换取令牌(accessToken)
				AccessGrant accessGrant = getConnectionFactory().getOAuthOperations().exchangeForAccess(code, returnToUrl, null);
				// TODO avoid API call if possible (auth using token would be fine)
				Connection<S> connection = getConnectionFactory().createConnection(accessGrant);
				return new SocialAuthenticationToken(connection, null);
			} catch (RestClientException e) {
				logger.debug("failed to exchange for access", e);
				return null;
			}
		} else {
			return null;
		}
	}

第一次访问时没有code参数会跳转到授权页面,若携带code参数则会进行申请令牌操作,AccessGrant其实就是封装了accessToken的实体类

####OAuth2AuthenticationService调用的QQConnectionFactory是如何注入进去的 ConnectionFactory在QQAutoConfiguration中进行配置,其父类SocialAutoConfigurerAdapter会调用addConnectionFactories方法 把ConnectionFactory放入到ConnectionFactoryLocator(ConnectionFactoryRegistry)中的Map集合connectionFactories中 以下是代码 #####QQAutoConfiguration(自定义)

public class QQAutoConfiguration extends SocialAutoConfigurerAdapter {
    
    ...
    
    /**
    	 * 创建QQConnectionFactory
    	 * 父类的addConnectionFactories方法会将QQConnectionFactory加入到ConnectionFactoryConfigurer中
    	 * @return
    	 */
    	@Override
    	protected ConnectionFactory<?> createConnectionFactory() {
    		QQProperties qqConfig = securityProperties.getSocial().getQq();
    		return new QQConnectionFactory(qqConfig.getProviderId(), qqConfig.getAppId(), qqConfig.getAppSecret());
    	}
}

看下父类SocialAutoConfigurerAdapter #####SocialAutoConfigurerAdapter

    @Override
	public void addConnectionFactories(ConnectionFactoryConfigurer configurer,
			Environment environment) {
        //这里的configurer其实就是SecurityEnabledConnectionFactoryConfigurer
		configurer.addConnectionFactory(createConnectionFactory());
	}

	protected abstract ConnectionFactory<?> createConnectionFactory();

看看SecurityEnabledConnectionFactoryConfigurer是如何将ConnectionFactory注入给OAuthenticationService的 #####SecurityEnabledConnectionFactoryConfigurer

    private SocialAuthenticationServiceRegistry registry;
	...
	public void addConnectionFactory(ConnectionFactory<?> connectionFactory) {
	    //将SocialAuthenticationService加入到SocialAuthenticationServiceRegistry中的authenticationServices集合中
		registry.addAuthenticationService(wrapAsSocialAuthenticationService(connectionFactory));
	}
	...
	private <A> SocialAuthenticationService<A> wrapAsSocialAuthenticationService(ConnectionFactory<A> cf) {
		if (cf instanceof OAuth1ConnectionFactory) {
			return new OAuth1AuthenticationService<A>((OAuth1ConnectionFactory<A>) cf);
		} else if (cf instanceof OAuth2ConnectionFactory) {
		    
		    //这里就是真正的把QQConnectionFactory注入到OAuth2AuthenticationService中
			final OAuth2AuthenticationService<A> authService = new OAuth2AuthenticationService<A>((OAuth2ConnectionFactory<A>) cf);
			authService.setDefaultScope(((OAuth2ConnectionFactory<A>) cf).getScope());
			return authService;
		}
		throw new IllegalArgumentException("The connection factory must be one of OAuth1ConnectionFactory or OAuth2ConnectionFactory");
	}

这里SecurityEnabledConnectionFactoryConfigurer主要完成了2件事: 1.初始化了OAuth2AuthenticationService,把ConnectionFactory注入到了其中 2.把OAuth2AuthenticationService注入到SocialAuthenticationServiceRegistry的Map集合authenticationServices中

####而SocialAuthenticationFilter又是如何拿到带有authenticationServices集合的SocialAuthenticationServiceRegistry呢

public class SpringSocialConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
    
    ...
    
    @Override
    	public void configure(HttpSecurity http) throws Exception {		
    		ApplicationContext applicationContext = http.getSharedObject(ApplicationContext.class);
    		UsersConnectionRepository usersConnectionRepository = getDependency(applicationContext, UsersConnectionRepository.class);
    		//从容器中获取SocialAuthenticationServiceLocator(SocialAuthenticationServiceRegistry)
    		**SocialAuthenticationServiceLocator authServiceLocator = getDependency(applicationContext, SocialAuthenticationServiceLocator.class);**
    		SocialUserDetailsService socialUsersDetailsService = getDependency(applicationContext, SocialUserDetailsService.class);
    		
    		//将从容器中获取的SocialAuthenticationServiceLocator传入SocialAuthenticationFilter构造函数
    		SocialAuthenticationFilter filter = new SocialAuthenticationFilter(
    				http.getSharedObject(AuthenticationManager.class), 
    				userIdSource != null ? userIdSource : new AuthenticationNameUserIdSource(), 
    				usersConnectionRepository, 
    				authServiceLocator);
    		
    		...
    		
    		//注册SocialAuthenticationFilter
    		http.authenticationProvider(
            				new SocialAuthenticationProvider(usersConnectionRepository, socialUsersDetailsService))
            			.addFilterBefore(postProcess(filter), AbstractPreAuthenticatedProcessingFilter.class);
}

可以看到SocialAuthenticationFilter中的SocialAuthenticationServiceRegistry是在容器中获取的,那SocialAuthenticationServiceRegistry又是在哪里注册的呢 打开org.springframework.social.config.annotation包下的SocialConfiguration类可以看到 #####SocialConfiguration

@Configuration
public class SocialConfiguration {
    ...
    @Bean
    	public ConnectionFactoryLocator connectionFactoryLocator() {
    		if (securityEnabled) {
    			SecurityEnabledConnectionFactoryConfigurer cfConfig = new SecurityEnabledConnectionFactoryConfigurer();
    			for (SocialConfigurer socialConfigurer : socialConfigurers) {
    				socialConfigurer.addConnectionFactories(cfConfig, environment);
    			}
    			return cfConfig.getConnectionFactoryLocator();
    		} else {
    			DefaultConnectionFactoryConfigurer cfConfig = new DefaultConnectionFactoryConfigurer();
    			for (SocialConfigurer socialConfigurer : socialConfigurers) {
    				socialConfigurer.addConnectionFactories(cfConfig, environment);
    			}
    			return cfConfig.getConnectionFactoryLocator();
    		}
    	}
}

ConnectionFactoryLocator其实就是SocialAuthenticationServiceLocator的父接口

####ProviderSignInUtils工具类 Social中的一个工具类,用户登录以后可以通过次类获取用户信息

###绑定与解绑 org.springframework.social.connect.web.ConnectController默认实现了获取用户绑定信息的控制器

@Controller
@RequestMapping("/connect")
public class ConnectController implements InitializingBean {
    //...
    
    @RequestMapping(method=RequestMethod.GET)
    	public String connectionStatus(NativeWebRequest request, Model model) {
    		setNoCache(request);
    		processFlash(request, model);
    		Map<String, List<Connection<?>>> connections = connectionRepository.findAllConnections();
    		model.addAttribute("providerIds", connectionFactoryLocator.registeredProviderIds());		
    		model.addAttribute("connectionMap", connections);
    		//返回connect/status的视图
    		return connectView();
    	}
}

这个控制器默认返回当前用户绑定信息,自己定义一个connect/status的视图

/**
 * 接收绑定信息的视图
 */
@Component("connect/status")
public class ImoocConnectionStatusView extends AbstractView {
	
	@Autowired
	private ObjectMapper objectMapper;

	@SuppressWarnings("unchecked")
	@Override
	protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		
		Map<String, List<Connection<?>>> connections = (Map<String, List<Connection<?>>>) model.get("connectionMap");
		
		Map<String, Boolean> result = new HashMap<>();
		for (String key : connections.keySet()) {
			result.put(key, CollectionUtils.isNotEmpty(connections.get(key)));
		}
		
		response.setContentType("application/json;charset=UTF-8");
		response.getWriter().write(objectMapper.writeValueAsString(result));
	}
}

绑定

@Controller
@RequestMapping("/connect")
public class ConnectController implements InitializingBean {
   
    //...
   
    @RequestMapping(value="/{providerId}", method=RequestMethod.GET)
    	public String connectionStatus(@PathVariable String providerId, NativeWebRequest request, Model model) {
    		setNoCache(request);
    		processFlash(request, model);
    		List<Connection<?>> connections = connectionRepository.findConnections(providerId);
    		setNoCache(request);
    		if (connections.isEmpty()) {
    			return connectView(providerId); 
    		} else {
    			model.addAttribute("connections", connections);
    			return connectedView(providerId);			
    		}
    	}
    	
    	//...
}

Spring Social默认实现了connect/{providerId}的控制,返回connect/{providerId}Connected的视图

###Session管理

可在配置文件中配置如下设置超时时间,少于60s按60s算 server.session.timeout = 600

在配置文件中配置session的类型,推荐Redis spring.session.store-type = none

#Spring Security OAuth2 ![](images/Spring Security OAuth2.JPG)

![](images/Spring Security自定义认证、资源服务器.JPG)

###Spring Security OAuth2原理 ![](images/Spring Security OAuth2原理.JPG) 蓝色部分为接口以及实现类

###重构Spring Security OAuth2 ![](images/重构Spring Securty OAuth2.JPG)

空文件

简介

慕课 security 展开 收起
Java
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Java
1
https://gitee.com/shiquanliao/imooc-security.git
git@gitee.com:shiquanliao/imooc-security.git
shiquanliao
imooc-security
imooc-security
master

搜索帮助