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 |
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 |
36 |
37 |
38 |
39 | 手机登录
40 |
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 extends GrantedAuthority> 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 extends GrantedAuthority> 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 extends Payload>[] 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 |
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 |
36 |
37 |
38 |
39 | 手机登录
40 |
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 |
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
--------------------------------------------------------------------------------