├── oauth2-server ├── readme.md ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── company │ │ │ ├── repository │ │ │ └── MemberRepository.java │ │ │ ├── Oauth2ServerApplication.java │ │ │ ├── domain │ │ │ ├── Role.java │ │ │ └── Member.java │ │ │ ├── controller │ │ │ ├── OauthClientDetailsController.java │ │ │ └── TokenController.java │ │ │ ├── conf │ │ │ ├── DataStoreConfig.java │ │ │ └── AuthAuthorizeConfig.java │ │ │ └── service │ │ │ └── CustomUserDetailsService.java │ │ └── resources │ │ ├── config │ │ └── application.yml │ │ └── logback.xml ├── test │ └── java │ │ └── ClientDetailUtils.java └── pom.xml ├── Oauth2学习 ├── http │ ├── 客户端认证方式.png │ └── 密码认证方式.png ├── 流程图 │ ├── Oauth2认证授权流程图.pdf │ ├── Oauth2认证授权流程图.png │ └── Oauth2认证授权流程图[浏览器打开].svg ├── 学习笔记 │ ├── Oauth2源码学习笔记.md │ └── Oauth2认证授权流程相关Bean解读.md └── 初始化数据库 │ └── initDataBase.sql ├── readme.md ├── oauth2-client ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── company │ │ │ ├── controller │ │ │ ├── TestController.java │ │ │ └── Oauth2Controller.java │ │ │ ├── Oauth2ClientApplication.java │ │ │ ├── config │ │ │ └── InterceptorRegisterConfiguration.java │ │ │ └── filter │ │ │ └── Oauth2Interceptor.java │ │ └── resources │ │ └── application.yml └── pom.xml ├── oauth-common-http ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── company │ └── utils │ ├── ResponseUtils.java │ ├── ApplicationSupport.java │ └── Oauth2Utils.java └── pom.xml /oauth2-server/readme.md: -------------------------------------------------------------------------------- 1 | 本服务器只是认证授权服务器.[搭建教程](http://www.jianshu.com/p/734348fb6cbb) -------------------------------------------------------------------------------- /Oauth2学习/http/客户端认证方式.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zth390872451/oauth2-redis-mysql/HEAD/Oauth2学习/http/客户端认证方式.png -------------------------------------------------------------------------------- /Oauth2学习/http/密码认证方式.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zth390872451/oauth2-redis-mysql/HEAD/Oauth2学习/http/密码认证方式.png -------------------------------------------------------------------------------- /Oauth2学习/流程图/Oauth2认证授权流程图.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zth390872451/oauth2-redis-mysql/HEAD/Oauth2学习/流程图/Oauth2认证授权流程图.pdf -------------------------------------------------------------------------------- /Oauth2学习/流程图/Oauth2认证授权流程图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zth390872451/oauth2-redis-mysql/HEAD/Oauth2学习/流程图/Oauth2认证授权流程图.png -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 基础架构: 2 | Spring Boot + Spring Security Oauth2 + Mysql + Redis 3 | Mysql:存储 ClientDetails 和 UserDetails 认证信息 4 | Redis:存储 AccessToken、RefreshToken、Authentication等凭证信息。 5 | spring security 企业级应用安全架构.pdf[http://www.doc88.com/p-0671914829759.html] -------------------------------------------------------------------------------- /oauth2-server/src/main/java/com/company/repository/MemberRepository.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.company.repository; 5 | 6 | import com.company.domain.Member; 7 | import org.springframework.data.jpa.repository.JpaRepository; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component("memberRepository") 11 | public interface MemberRepository extends JpaRepository { 12 | Member findOneByUsername(String username); 13 | } 14 | -------------------------------------------------------------------------------- /oauth2-client/src/main/java/com/company/controller/TestController.java: -------------------------------------------------------------------------------- 1 | package com.company.controller; 2 | 3 | import org.springframework.web.bind.annotation.RequestMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | /** 7 | * 测试接口 8 | */ 9 | @RestController 10 | @RequestMapping("/api") 11 | public class TestController { 12 | 13 | @RequestMapping("/test") 14 | public String test(){ 15 | return "success"; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /oauth2-client/src/main/java/com/company/Oauth2ClientApplication.java: -------------------------------------------------------------------------------- 1 | package com.company; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client; 6 | 7 | 8 | @SpringBootApplication 9 | @EnableOAuth2Client //创建Oauth2的资源服务器——client,并开启资源服务器的相关默认配置 10 | public class Oauth2ClientApplication { 11 | public static void main(String[] args) { 12 | SpringApplication.run(Oauth2ClientApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /oauth2-server/src/main/java/com/company/Oauth2ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.company; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; 6 | 7 | @SpringBootApplication 8 | @EnableAuthorizationServer //创建Oauth2的认证授权服务器——provider,并开启认证授权服务器的相关默认配置 9 | public class Oauth2ServerApplication { 10 | public static void main(String[] args) { 11 | SpringApplication.run(Oauth2ServerApplication.class, args); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /oauth2-server/src/main/java/com/company/domain/Role.java: -------------------------------------------------------------------------------- 1 | package com.company.domain; 2 | 3 | import org.springframework.security.core.GrantedAuthority; 4 | 5 | import java.util.HashSet; 6 | import java.util.Set; 7 | 8 | //默认角色 9 | public class Role implements GrantedAuthority { 10 | 11 | private static final long serialVersionUID = -2633659220734280260L; 12 | 13 | private Set roles = new HashSet(); 14 | 15 | @Override 16 | public String getAuthority() { 17 | return "USER"; 18 | } 19 | 20 | public Set getRoles() { 21 | return roles; 22 | } 23 | 24 | public void setRoles(Set roles) { 25 | this.roles = roles; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /oauth2-client/src/main/java/com/company/config/InterceptorRegisterConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.company.config; 2 | 3 | import com.company.filter.Oauth2Interceptor; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 6 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 7 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 8 | 9 | @Configuration 10 | @EnableWebMvc //开启spring mvc的相关默认配置 11 | public class InterceptorRegisterConfiguration extends WebMvcConfigurerAdapter { 12 | 13 | @Override 14 | public void addInterceptors(InterceptorRegistry registry) { 15 | registry.addInterceptor(new Oauth2Interceptor()) 16 | .excludePathPatterns("/api/oauth2/**");//添加Oauth2Interceptor,除了/api/oauth2/**下的接口都需要进行 AccessToken 的校验 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /oauth2-server/src/main/resources/config/application.yml: -------------------------------------------------------------------------------- 1 | security: 2 | basic: 3 | enabled: false # 是否开启基本的鉴权,默认为true。 true:所有的接口默认都需要被验证,将导致 拦截器[对于 excludePathPatterns()方法失效] 4 | server: 5 | context-path: /oauth2-server 6 | port: 8050 7 | --- 8 | spring: 9 | application: 10 | name: oauth2-server 11 | redis: 12 | database: 5 13 | host: 127.0.0.1 14 | password: root123456 15 | port: 6379 16 | pool: 17 | max-active: 8 18 | max-wait: 8 19 | min-idle: 0 20 | max-idle: 8 21 | 22 | datasource: 23 | url: jdbc:mysql://127.0.0.1:3306/redis-oauth2?useUnicode=true&characterEncoding=UTF-8 24 | username: root 25 | password: 123456 26 | jpa: 27 | database-platform: org.hibernate.dialect.MySQL5InnoDBDialect 28 | database: MYSQL 29 | openInView: true 30 | show_sql: true 31 | generate-ddl: true #(false) 32 | hibernate: 33 | ddl-auto: update #(none) -------------------------------------------------------------------------------- /oauth2-client/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | security: 2 | basic: 3 | enabled: false # 是否开启基本的鉴权,默认为true。 true:所有的接口默认都需要被验证,将导致 拦截器[对于 excludePathPatterns()方法失效] 4 | server: 5 | context-path: /oauth2-client 6 | port: 8051 7 | --- 8 | spring: 9 | application: 10 | name: oauth2-client 11 | datasource: #数据源的配置 12 | url: jdbc:mysql://127.0.0.1:3306/redis-oauth2?useUnicode=true&characterEncoding=UTF-8 13 | username: root 14 | password: 123456 15 | jpa: #jpa的支持:hibernate的相关配置 16 | database-platform: org.hibernate.dialect.MySQL5InnoDBDialect 17 | database: MYSQL 18 | openInView: true 19 | show_sql: true 20 | generate-ddl: true #(false) 21 | hibernate: 22 | ddl-auto: update #(none) 23 | 24 | oauth: #oauth2-server认证授权服务器的url配置,在获取AccessToken以及检测AccessToken中会用到 25 | token: http://127.0.0.1:8050/oauth2-server/oauth/token 26 | check_token: http://localhost:8050/oauth2-server/oauth/check_token #检查AccessToken有效性的url(认证授权服务器的url地址),获取 AccessToken 对象 27 | -------------------------------------------------------------------------------- /oauth2-server/test/java/ClientDetailUtils.java: -------------------------------------------------------------------------------- 1 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 2 | import org.springframework.security.crypto.password.PasswordEncoder; 3 | 4 | /** 5 | * Created by Administrator on 2017/7/7 0007. 6 | */ 7 | public class ClientDetailUtils { 8 | 9 | //client_id 和 client_secret 生成 10 | public static void main(String[] args) { 11 | String password = "123456"; 12 | PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); 13 | String hashedPassword = passwordEncoder.encode(password); 14 | System.out.println(hashedPassword); 15 | } 16 | 17 | /* 18 | 插入数据库 19 | INSERT INTO `redis-oauth2`.`oauth_client_details` (`client_id`, `resource_ids`, `client_secret`, `scope`, `authorized_grant_types`, `web_server_redirect_uri`, `authorities`, `access_token_validity`, `refresh_token_validity`, `additional_information`, `autoapprove`) VALUES ('client_auth_mode', '', '$2a$10$ei2IVxChXOklD2QPR4l4TOdEE8CdlREIEy775v5GfMnpSBX1misoy', 'read,write', 'client_credentials,refresh_token', NULL, 'USER', '3600', NULL, NULL, NULL); 20 | */ 21 | } 22 | -------------------------------------------------------------------------------- /oauth2-server/src/main/java/com/company/domain/Member.java: -------------------------------------------------------------------------------- 1 | package com.company.domain; 2 | 3 | 4 | import javax.persistence.*; 5 | import java.io.Serializable; 6 | 7 | 8 | /** 9 | * Entity - 会员 10 | * @author umeox 11 | */ 12 | @Entity 13 | @Table(name = "ux_member") 14 | public class Member implements Serializable{ 15 | @Id 16 | @GeneratedValue(strategy = GenerationType.AUTO) 17 | private Long id; 18 | private String username; 19 | private String password; 20 | 21 | public Member(Member member){ 22 | super(); 23 | this.username = member.getUsername(); 24 | this.password = member.getPassword(); 25 | } 26 | 27 | public Member() { 28 | 29 | } 30 | 31 | public String getUsername() { 32 | return username; 33 | } 34 | 35 | public void setUsername(String username) { 36 | this.username = username; 37 | } 38 | 39 | public String getPassword() { 40 | return password; 41 | } 42 | 43 | public void setPassword(String password) { 44 | this.password = password; 45 | } 46 | 47 | public Long getId() { 48 | return id; 49 | } 50 | 51 | public void setId(Long id) { 52 | this.id = id; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /oauth-common-http/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | oauth2.redis.mysql 7 | com.company.umeox 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | oauth-common-http 13 | 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-web 18 | 19 | 20 | org.springframework.security.oauth 21 | spring-security-oauth2 22 | 2.0.13.RELEASE 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-jdbc 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /oauth2-server/src/main/java/com/company/controller/OauthClientDetailsController.java: -------------------------------------------------------------------------------- 1 | package com.company.controller; 2 | 3 | import org.springframework.web.bind.annotation.RequestMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | /** 7 | * 后续开发:提供接口,设置 client_id 和 client_secret 的相关接口 8 | */ 9 | @RestController 10 | @RequestMapping("/oauth2/clientDetails") 11 | public class OauthClientDetailsController { 12 | 13 | /* @Autowired 14 | private PasswordEncoder passwordEncoder; 15 | @Autowired 16 | private JdbcClientDetailsService jdbcClientDetailsService; 17 | 18 | 19 | @RequestMapping("/add") 20 | public BaseClientDetails addOauthClientDetails(String clientId,String resourceId,String scopes,String grantTypes, 21 | String authorities,String redirectUris,String secret){ 22 | String encodeSecret = passwordEncoder.encode(secret); 23 | BaseClientDetails clientDetails = new BaseClientDetails(clientId,resourceId,scopes,grantTypes,authorities,redirectUris); 24 | clientDetails.setClientSecret(encodeSecret); 25 | jdbcClientDetailsService.addClientDetails(clientDetails); 26 | return clientDetails; 27 | }*/ 28 | } 29 | -------------------------------------------------------------------------------- /oauth-common-http/src/main/java/com/company/utils/ResponseUtils.java: -------------------------------------------------------------------------------- 1 | package com.company.utils; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | 6 | import javax.servlet.http.HttpServletResponse; 7 | import java.io.IOException; 8 | import java.io.PrintWriter; 9 | 10 | /** 11 | * 响应Response工具类 12 | */ 13 | public class ResponseUtils { 14 | 15 | /** 16 | * 响应Http请求 17 | * @param response 18 | * @param resData 19 | * @throws JsonProcessingException 20 | */ 21 | public static void responseData(HttpServletResponse response, Object resData) throws JsonProcessingException { 22 | //将实体对象转换为jackson Object转换 23 | ObjectMapper objectMapper = new ObjectMapper(); 24 | String jsonString = objectMapper.writeValueAsString(resData); 25 | response.setCharacterEncoding("UTF-8"); 26 | response.setContentType("application/json; charset=utf-8"); 27 | PrintWriter out = null; 28 | try { 29 | out = response.getWriter(); 30 | out.append(jsonString); 31 | } catch (IOException e) { 32 | e.printStackTrace(); 33 | } finally { 34 | if (out != null) { 35 | out.close(); 36 | } 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /oauth2-client/src/main/java/com/company/filter/Oauth2Interceptor.java: -------------------------------------------------------------------------------- 1 | package com.company.filter; 2 | 3 | import com.company.utils.Oauth2Utils; 4 | import com.company.utils.ResponseUtils; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 7 | import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | 12 | /** 13 | * 对AccessToken进行检测,当出现AccessToken失效或者非法时,将直接返回401,未授权错误 14 | */ 15 | public class Oauth2Interceptor extends HandlerInterceptorAdapter { 16 | @Override 17 | public boolean preHandle(HttpServletRequest request, 18 | HttpServletResponse response, Object handler) throws Exception { 19 | String accessToken = request.getParameter("access_token"); 20 | OAuth2AccessToken oauth2AccessToken = Oauth2Utils.checkTokenInOauth2Client(accessToken); 21 | if (oauth2AccessToken==null){//非法的Token值 22 | response.setStatus(HttpStatus.UNAUTHORIZED.value()); 23 | ResponseUtils.responseData(response,"非法的Token!"); 24 | return false; 25 | }else if (oauth2AccessToken.isExpired()){//token失效 26 | response.setStatus(HttpStatus.UNAUTHORIZED.value()); 27 | ResponseUtils.responseData(response,"Token失效,请重新登录!"); 28 | return false; 29 | } 30 | return true; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.company.umeox 8 | oauth2.redis.mysql 9 | pom 10 | 1.0-SNAPSHOT 11 | 12 | oauth2-client 13 | oauth2-server 14 | oauth-common-http 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-parent 20 | 1.4.0.RELEASE 21 | 22 | 23 | 24 | 25 | 26 | mysql 27 | mysql-connector-java 28 | 5.1.27 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-maven-plugin 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /oauth2-server/src/main/java/com/company/controller/TokenController.java: -------------------------------------------------------------------------------- 1 | package com.company.controller; 2 | 3 | import com.company.utils.Oauth2Utils; 4 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 5 | import org.springframework.security.oauth2.provider.OAuth2Authentication; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestParam; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | @RestController 12 | @RequestMapping("/oauth") 13 | public class TokenController { 14 | 15 | /** 16 | * 覆盖了 spring-security-oauth2 内部的 endpoint oauth2/check_token 17 | * spring-security-oauth2 内部原有的该控制器 CheckTokenEndpoint,返回值,不符合自身业务要求,故覆盖之。 18 | */ 19 | @GetMapping("/check_token") 20 | public OAuth2AccessToken getToken(@RequestParam(value = "token") String token){ 21 | OAuth2AccessToken oAuth2AccessToken = Oauth2Utils.checkTokenInOauth2Server(token); 22 | return oAuth2AccessToken; 23 | } 24 | 25 | /** 26 | * 获取当前token对应的用户主体的凭证信息(认证对象) 27 | */ 28 | @GetMapping("/getAuth") 29 | public OAuth2Authentication getAuth(@RequestParam(value = "token") String token){ 30 | OAuth2Authentication oAuth2Authentication = Oauth2Utils.getAuthenticationInOauth2Server(token); 31 | return oAuth2Authentication; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /oauth-common-http/src/main/java/com/company/utils/ApplicationSupport.java: -------------------------------------------------------------------------------- 1 | package com.company.utils; 2 | 3 | import org.springframework.beans.BeansException; 4 | import org.springframework.beans.factory.DisposableBean; 5 | import org.springframework.context.ApplicationContext; 6 | import org.springframework.context.ApplicationContextAware; 7 | import org.springframework.stereotype.Component; 8 | import org.springframework.util.Assert; 9 | 10 | /** 11 | * 获取Spring容器管理的Bean对象,应用中配置参数 12 | **/ 13 | @Component 14 | public class ApplicationSupport implements DisposableBean, ApplicationContextAware { 15 | 16 | private static ApplicationContext applicationContext; 17 | // 获取配置文件参数值 18 | public static String getParamVal(String paramKey){ 19 | return applicationContext.getEnvironment().getProperty(paramKey); 20 | } 21 | 22 | // 获取bean对象 23 | public static Object getBean(String name) { 24 | Assert.hasText(name); 25 | return applicationContext.getBean(name); 26 | } 27 | 28 | public static T getBean(Class clazz) { 29 | return applicationContext.getBean(clazz); 30 | } 31 | 32 | @Override 33 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 34 | this.applicationContext = applicationContext; 35 | } 36 | 37 | @Override 38 | public void destroy() throws Exception { 39 | applicationContext = null; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /oauth2-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | oauth2.redis.mysql 7 | com.company.umeox 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | oauth2-client 13 | 14 | 15 | 16 | 17 | org.springframework.boot 18 | spring-boot-starter-web 19 | 20 | 21 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-data-jpa 31 | 32 | 33 | com.company.umeox 34 | oauth-common-http 35 | 1.0-SNAPSHOT 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Oauth2学习/学习笔记/Oauth2源码学习笔记.md: -------------------------------------------------------------------------------- 1 | Spring Security Oauth2 + Mysql + Redis 认证授权服务器的搭建 2 | 3 | Filter过滤器的处理流程: 4 | 5 | 实现了抽象类 AbstractAuthenticationProcessingFilter 的模板方法的 6 | 子类: 7 | 1、ClientCredentialsTokenEndpointFilter : 此过滤器在 spring-security-oauth2 包 8 | 顾名思义,客户端认证,使用请求的凭证去获取AccessToken的时候,将被该过滤器过滤。 9 | 当客户端采用 客户端信任模式申请AccessToken的时候【发送Http到类 TokenEndpoint的控制器,映射 /oauth/token url的链接请求】,将被此过滤器过滤 10 | 2、OAuth2ClientAuthenticationProcessingFilter:此过滤器在 spring-security-oauth2 包 11 | 当用户已认证成功,获取AccessToken之后,使用 AccessToken 去检查有效性【/oauth/check_token】时,将被过滤 12 | 3、UsernamePasswordAuthenticationFilter:此过滤器在 spring-security-web包 13 | 对于登陆请求"/login"的过滤 14 | 15 | 上述的三个过滤器均实现了抽象类AbstractAuthenticationProcessingFilter中的模板方法: attemptAuthentication(request, response);, 16 | 在过滤器执行的过程【doFilter】中,将调用 模板方法authResult = attemptAuthentication(request, response); 17 | 而模板方法内部最底部则调用:this.getAuthenticationManager().authenticate(authRequest)方法进行数据信息的认证; 18 | 19 | AuthenticationManager 接口:定义了一个认证方法:对根据http请求参数构造出的Authentication进行认证。 20 | ProviderManager 类:用于管理所有实现了 AuthenticationManager 接口的类,在认证时,迭代调用 实现类,进行认证。 21 | 在认证过程中最 22 | AbstractUserDetailsAuthenticationProvider 抽象类实现了 AuthenticationManager 接口, 23 | 并定义了模板方法 UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication); 24 | 在认证接口 AuthenticationManager 的实现类中,最重要的类是 DaoAuthenticationProvider. 25 | 26 | DaoAuthenticationProvider 类: 实现了模板方法 retrieveUser。 27 | 而在实现的过程中,调用了 UserDetailsService 接口的实现类方法 loadUserByUsername, 28 | 该方法用于从目标存储地址获取 UserDetails。 29 | 而目标存储地址,可能为 数据库、缓存、内存。 30 | UserDetailsService 接口 用于认证,可自定义实现类,灵活使用。 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /oauth2-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | oauth2.redis.mysql 7 | com.company.umeox 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | oauth2-server 13 | 14 | 15 | 1.0.14 16 | 17 | 18 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-data-jpa 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-data-redis 36 | 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-web 41 | 42 | 43 | 44 | com.alibaba 45 | druid 46 | ${com.alibaba.version} 47 | 48 | 49 | com.company.umeox 50 | oauth-common-http 51 | 1.0-SNAPSHOT 52 | 53 | 54 | -------------------------------------------------------------------------------- /oauth2-server/src/main/java/com/company/conf/DataStoreConfig.java: -------------------------------------------------------------------------------- 1 | package com.company.conf; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.data.redis.cache.RedisCache; 6 | import org.springframework.data.redis.connection.RedisConnectionFactory; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | import org.springframework.security.core.userdetails.UserCache; 9 | import org.springframework.security.core.userdetails.cache.SpringCacheBasedUserCache; 10 | import org.springframework.security.oauth2.provider.token.TokenStore; 11 | import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore; 12 | 13 | @Configuration 14 | public class DataStoreConfig { 15 | 16 | public static final String REDIS_CACHE_NAME="redis_cache_name";//不为null即可 17 | public static final String REDIS_PREFIX ="redis_cache_prefix";//不为null即可 18 | public static final Long EXPIRE =60*60L;//缓存有效时间 19 | 20 | /** 21 | * 配置用以存储用户认证信息的缓存 22 | */ 23 | @Bean 24 | RedisCache redisCache(RedisTemplate redisTemplate){ 25 | RedisCache redisCache = new RedisCache(REDIS_CACHE_NAME,REDIS_PREFIX.getBytes(),redisTemplate,EXPIRE); 26 | return redisCache; 27 | } 28 | /** 29 | * 30 | * 创建UserDetails存储服务的Bean:使用Redis作为缓存介质 31 | * UserDetails user = this.userCache.getUserFromCache(username) 32 | */ 33 | @Bean 34 | public UserCache userCache(RedisCache redisCache) throws Exception { 35 | UserCache userCache = new SpringCacheBasedUserCache(redisCache); 36 | return userCache; 37 | } 38 | 39 | /** 40 | * 配置AccessToken的存储方式:此处使用Redis存储 41 | * Token的可选存储方式 42 | * 1、InMemoryTokenStore 43 | * 2、JdbcTokenStore 44 | * 3、JwtTokenStore 45 | * 4、RedisTokenStore 46 | * 5、JwkTokenStore 47 | */ 48 | @Bean 49 | public TokenStore tokenStore(RedisConnectionFactory redisConnectionFactory) { 50 | return new RedisTokenStore(redisConnectionFactory); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Oauth2学习/初始化数据库/initDataBase.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat MySQL Data Transfer 3 | 4 | Source Server : 192.168.2.35 5 | Source Server Version : 50173 6 | Source Host : 192.168.2.35:3306 7 | Source Database : redis-oauth2 8 | 9 | Target Server Type : MYSQL 10 | Target Server Version : 50173 11 | File Encoding : 65001 12 | 13 | Date: 2017-05-13 11:41:42 14 | */ 15 | 16 | SET FOREIGN_KEY_CHECKS=0; 17 | 18 | -- ---------------------------- 19 | -- Table structure for oauth_client_details 20 | -- ---------------------------- 21 | DROP TABLE IF EXISTS `oauth_client_details`; 22 | CREATE TABLE `oauth_client_details` ( 23 | `client_id` varchar(255) NOT NULL, 24 | `resource_ids` varchar(255) DEFAULT NULL, 25 | `client_secret` varchar(255) DEFAULT NULL, 26 | `scope` varchar(255) DEFAULT NULL, 27 | `authorized_grant_types` varchar(255) DEFAULT NULL, 28 | `web_server_redirect_uri` varchar(255) DEFAULT NULL, 29 | `authorities` varchar(255) DEFAULT NULL, 30 | `access_token_validity` int(11) DEFAULT NULL, 31 | `refresh_token_validity` int(11) DEFAULT NULL, 32 | `additional_information` varchar(255) DEFAULT NULL, 33 | `autoapprove` varchar(255) DEFAULT NULL, 34 | PRIMARY KEY (`client_id`) 35 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 36 | 37 | -- ---------------------------- 38 | -- Records of oauth_client_details 39 | -- ---------------------------- 40 | INSERT INTO `oauth_client_details` VALUES ('client_auth_mode', null, '$2a$10$.GCl9SMgNUCavNgdP4hji.bQLl86HCs0gDWSO9BBbXk7Sn9Z0/zLq', 'read,write', 'client_credentials,refresh_token', null, 'USER', '2592000', null, null, null); 41 | INSERT INTO `oauth_client_details` VALUES ('password_auth_mode', '', '$2a$10$.GCl9SMgNUCavNgdP4hji.bQLl86HCs0gDWSO9BBbXk7Sn9Z0/zLq', 'read,write', 'refresh_token,password', null, 'USER', '2592000', null, null, null); 42 | 43 | 44 | DROP TABLE IF EXISTS `ux_member`; 45 | CREATE TABLE `ux_member` ( 46 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 47 | `password` varchar(255) DEFAULT NULL, 48 | `username` varchar(255) DEFAULT NULL, 49 | PRIMARY KEY (`id`) 50 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1; 51 | 52 | -- ---------------------------- 53 | -- Records of ux_member 54 | -- ---------------------------- 55 | INSERT INTO `redis-oauth2`.`ux_member` (`id`, `password`, `username`) VALUES ('1', 'e10adc3949ba59abbe56e057f20f883e', 'member_name'); 56 | -------------------------------------------------------------------------------- /oauth2-server/src/main/java/com/company/service/CustomUserDetailsService.java: -------------------------------------------------------------------------------- 1 | package com.company.service; 2 | 3 | import com.company.domain.Member; 4 | import com.company.domain.Role; 5 | import com.company.repository.MemberRepository; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.security.core.GrantedAuthority; 10 | import org.springframework.security.core.userdetails.UserDetails; 11 | import org.springframework.security.core.userdetails.UserDetailsService; 12 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 13 | import org.springframework.stereotype.Service; 14 | 15 | import java.util.Collection; 16 | 17 | 18 | @Service 19 | public class CustomUserDetailsService implements UserDetailsService { 20 | 21 | private static final Logger log = LoggerFactory.getLogger(CustomUserDetailsService.class); 22 | @Autowired 23 | private MemberRepository memberRepository; 24 | 25 | @Override 26 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 27 | Member member = memberRepository.findOneByUsername(username); 28 | if (member == null) { 29 | log.error("用户不存在"); 30 | throw new UsernameNotFoundException(String.format("User %s does not exist!", username)); 31 | } 32 | return new UserRepositoryUserDetails(member); 33 | } 34 | 35 | /** 36 | * 注意该类的层次结构,继承了Member并实现了UserDetails接口,继承是为了使用Member的username和password信息 37 | */ 38 | private final static class UserRepositoryUserDetails extends Member implements UserDetails { 39 | private static final long serialVersionUID = 1L; 40 | private UserRepositoryUserDetails(Member member) { 41 | super(member); 42 | } 43 | 44 | @Override 45 | public Collection getAuthorities() { 46 | Role role = new Role(); 47 | return role.getRoles(); 48 | } 49 | 50 | @Override 51 | public String getUsername() { 52 | return super.getUsername(); 53 | } 54 | 55 | @Override 56 | public boolean isAccountNonExpired() { 57 | return true; 58 | } 59 | 60 | @Override 61 | public boolean isAccountNonLocked() { 62 | return true; 63 | } 64 | 65 | @Override 66 | public boolean isCredentialsNonExpired() { 67 | return true; 68 | } 69 | 70 | @Override 71 | public boolean isEnabled() { 72 | return true; 73 | } 74 | 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /oauth2-server/src/main/java/com/company/conf/AuthAuthorizeConfig.java: -------------------------------------------------------------------------------- 1 | package com.company.conf; 2 | 3 | import com.company.service.CustomUserDetailsService; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.security.authentication.AuthenticationManager; 7 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 8 | import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; 9 | import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; 10 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; 11 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; 12 | import org.springframework.security.oauth2.provider.token.TokenStore; 13 | 14 | import javax.sql.DataSource; 15 | 16 | @Configuration 17 | 18 | public class AuthAuthorizeConfig extends AuthorizationServerConfigurerAdapter { 19 | 20 | @Autowired 21 | DataSource dataSource; 22 | @Autowired 23 | private AuthenticationManager authenticationManager; 24 | @Autowired 25 | private TokenStore tokenStore; 26 | @Autowired 27 | private CustomUserDetailsService userDetailsService; 28 | 29 | /** 30 | * 配置 oauth_client_details【client_id和client_secret等】信息的认证【检查ClientDetails的合法性】服务 31 | * 设置 认证信息的来源:数据库 (可选项:数据库和内存,使用内存一般用来作测试) 32 | * 自动注入:ClientDetailsService的实现类 JdbcClientDetailsService (检查 ClientDetails 对象) 33 | */ 34 | @Override 35 | public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 36 | clients.jdbc(dataSource); 37 | } 38 | 39 | 40 | /** 41 | * 密码模式下配置认证管理器 AuthenticationManager,并且设置 AccessToken的存储介质tokenStore,如果不设置,则会默认使用内存当做存储介质。 42 | * 而该AuthenticationManager将会注入 2个Bean对象用以检查(认证) 43 | * 1、ClientDetailsService的实现类 JdbcClientDetailsService (检查 ClientDetails 对象) 44 | * 2、UserDetailsService的实现类 CustomUserDetailsService (检查 UserDetails 对象) 45 | * 46 | */ 47 | @Override 48 | public void configure(AuthorizationServerEndpointsConfigurer endpoints) 49 | throws Exception { 50 | endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore).userDetailsService(userDetailsService); 51 | } 52 | 53 | /** 54 | * 配置:安全检查流程 55 | * 默认过滤器:BasicAuthenticationFilter 56 | * 1、oauth_client_details表中clientSecret字段加密【ClientDetails属性secret】 57 | * 2、CheckEndpoint类的接口 oauth/check_token 无需经过过滤器过滤,默认值:denyAll() 58 | */ 59 | @Override 60 | public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { 61 | security.allowFormAuthenticationForClients();//允许客户表单认证 62 | security.passwordEncoder(new BCryptPasswordEncoder());//设置oauth_client_details中的密码编码器 63 | security.checkTokenAccess("permitAll()");//对于CheckEndpoint控制器[框架自带的校验]的/oauth/check端点允许所有客户端发送器请求而不会被Spring-security拦截 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /oauth2-server/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | utf-8 13 | ${CONSOLE_LOG_PATTERN} 14 | 15 | 16 | 17 | 18 | 19 | 20 | oauth2-server.%d{yyyy-MM-dd}.log 21 | 30 22 | 23 | 24 | utf-8 25 | ${FILE_LOG_PATTERN} 26 | 27 | 28 | 29 | 512 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | true 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /Oauth2学习/学习笔记/Oauth2认证授权流程相关Bean解读.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | /*******************************认证流程服务相关信息【BasicAuthenticationFilter类中涉及的Bean的相关解读】***********************************/ 4 | 5 | FilterChainProxy:一个过滤器执行的工具类。 6 | class FilterChainProxy{ 7 | 拥有 List filterChains;过滤器链的列表【包含多个过滤器链】 8 | 而过滤器链 FilterChain 是包含过滤器的集合。 9 | 处理流程: 10 | 1、迭代过滤器链列表,选择合适的过滤器链 11 | 2、迭代过滤器链,选择合适的过滤器进行过滤 12 | for (SecurityFilterChain chain : filterChains) { 13 | //寻找合适的过滤器链 14 | if (chain.matches(request)) { 15 | for (Filter filter : filterChains) { 16 | void doFilter(ServletRequest request, ServletResponse response){ 17 | //迭代查找匹配的过滤器 18 | if(filter.matches(HttpServletRequest request)){ 19 | filter.doFilter(request, response) 20 | } 21 | } 22 | } 23 | } 24 | } 25 | 26 | 在Oauth认证的过程中,重要的过滤器是:BasicAuthenticationFilter,对向Oauth2服务器 27 | 申请AccessToken的Http请求进行过滤操作,过滤操作中,主要是进行数据校验(认证),保护信息安全。 28 | 29 | BasicAuthenticationFilter 简要处理逻辑: 30 | 1、处理 包含 Basic 请求头的 HTTP request请求, 并将结果存入 SecurityContextHolder 31 | 2、Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== Basic后的字符为 username:password base64编码的字符串 32 | 3、调用认证管理器的authenticate方法对http请求进行认证,并返回认证结果 33 | 4、认证成功,则提交给下一个过滤器,继续过滤;认证失败则抛出异常。 34 | 5、后续过滤器全部认证成功,则映射到具体的控制器的接口【TokenEndpoint类的 oauth/token接口】进行处理 35 | 基础认证过滤器类 :BasicAuthenticationFilter: 36 | doFilterInternal(HttpServletRequest request,HttpServletResponse response, FilterChain chain) 37 | { 38 | 认证器提供者管理类:ProviderManager 39 | { 40 | //对认证器集合进行迭代选择合适的 AuthenticationProvider,认证的过程是:AuthenticationProvider 调用内部的业务类【有默认实现类,也可自定义】进行数据校验 41 | for (AuthenticationProvider provider : getProviders()){ 42 | Authentication result = provider.authenticate(authentication); 43 | } 44 | 认证器提供者:AuthenticationProvider 45 | 使用默认的实现类:DaoAuthenticationProvider 的 retrieveUser() 模板方法 46 | UserDetails retrieveUser(username,authentication){ 47 | //使用 UserDetailsService实现类,从指定存储介质【数据库(Mysql、Oracle)、缓存(Redis)、内存(Memory)】中 加载数据进行校验。 48 | loadedUser = this.getUserDetailsService().loadUserByUsername(username); 49 | } 50 | } 51 | 52 | /*******************************授权流程服务相关配置【TokenEndpoint类中/oauth/token接口涉及的Bean的相关解读】***********************************/ 53 | 54 | TokenEndpoint: 55 | oauth/token 接口: 56 | 1、进行认证逻辑【UserDetailsService.loadUserByUsername】 57 | 2、认证成功,根据认证类型grant_type,则调用相应的凭证生成器 TokenGrant 根据认证信息,生成 AccessToken,并存储在指定的存储介质【1、数据库(Mysql|Oracle) 2、内存 3、Redis】中。 58 | 2.1、TokenGrant接口: 59 | 2.1.1、抽象类:AbstractTokenGranter: 60 | 2.1.2、具体子类: 61 | a、AuthorizationCodeTokenGranter:处理 grant_type 为 authorization_code 的请求 62 | b、ClientCredentialsTokenGranter:处理 grant_type 为 client_credentials 的请求 63 | c、ResourceOwnerPasswordTokenGranter:处理 grant_type 为 client_credentials 的请求 64 | d、ImplicitTokenGranter:处理 grant_type 为 implicit 的请求 65 | e、RefreshTokenGranter:处理 grant_type 为 refresh_token 的请求 66 | 3、认证失败 67 | 68 | TokenStore:配置AccessToken的存储方式【可选存储方式如下】: 69 | 1、InMemoryTokenStore 70 | 2、JdbcTokenStore 71 | 3、JwtTokenStore 72 | 4、RedisTokenStore 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /oauth-common-http/src/main/java/com/company/utils/Oauth2Utils.java: -------------------------------------------------------------------------------- 1 | package com.company.utils; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 6 | import org.springframework.security.oauth2.provider.OAuth2Authentication; 7 | import org.springframework.security.oauth2.provider.token.TokenStore; 8 | import org.springframework.util.StringUtils; 9 | import org.springframework.web.client.RestTemplate; 10 | 11 | /** 12 | * Created by Administrator on 2017/5/5. 13 | */ 14 | public class Oauth2Utils { 15 | 16 | private static final Logger LOGGER = LoggerFactory.getLogger(Oauth2Utils.class); 17 | //检查AccessToken有效性的url(认证授权服务器的url地址) 18 | private static String checkTokenUrl ; 19 | static { 20 | checkTokenUrl = ApplicationSupport.getParamVal("oauth.check_token"); 21 | } 22 | 23 | /** 24 | * oauth2 认证服务器直接处理校验请求的逻辑 25 | * @param accessToken 26 | * @return 27 | */ 28 | public static OAuth2AccessToken checkTokenInOauth2Server(String accessToken){ 29 | TokenStore tokenStore = (TokenStore) ApplicationSupport.getBean("tokenStore"); 30 | OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(accessToken); 31 | return oAuth2AccessToken; 32 | } 33 | 34 | /** 35 | * oauth2 认证服务器直接处理校验请求的逻辑 36 | * @param accessToken 37 | * @return 38 | */ 39 | public static OAuth2Authentication getAuthenticationInOauth2Server(String accessToken){ 40 | TokenStore tokenStore = (TokenStore) ApplicationSupport.getBean("tokenStore"); 41 | OAuth2Authentication oAuth2Authentication = tokenStore.readAuthentication(accessToken); 42 | return oAuth2Authentication; 43 | } 44 | 45 | /** 46 | * 客户端申请校验 47 | * @param tokenValue 48 | * @return 49 | */ 50 | public static OAuth2Authentication getAuthenticationInOauth2Client(String tokenValue){ 51 | if (StringUtils.isEmpty(tokenValue)) { 52 | return null; 53 | } 54 | try { 55 | RestTemplate restTemplate = new RestTemplate(); 56 | OAuth2Authentication oAuth2Authentication = restTemplate.getForObject(checkTokenUrl+"?token="+tokenValue, OAuth2Authentication.class); 57 | return oAuth2Authentication; 58 | }catch (Exception e){ 59 | LOGGER.error("getAuthenticationInOauth2Client failure:",e); 60 | return null; 61 | } 62 | } 63 | 64 | /** 65 | * 客户端申请校验 66 | * @param tokenValue 67 | * @return 68 | */ 69 | public static OAuth2AccessToken checkTokenInOauth2Client(String tokenValue){ 70 | if (StringUtils.isEmpty(tokenValue)) { 71 | return null; 72 | } 73 | try { 74 | RestTemplate restTemplate = new RestTemplate(); 75 | OAuth2AccessToken oAuth2AccessToken = restTemplate.getForObject(checkTokenUrl+"?token="+tokenValue, OAuth2AccessToken.class); 76 | return oAuth2AccessToken; 77 | }catch (Exception e){ 78 | LOGGER.error("checkTokenInOauth2Client failure:",e); 79 | return null; 80 | } 81 | } 82 | 83 | /** 84 | * 获取 OAuth2AccessToken 85 | * @param tokenValue 86 | * @return OAuth2AccessToken 87 | */ 88 | public static OAuth2AccessToken readAccessToken(String tokenValue){ 89 | TokenStore tokenStore = (TokenStore) ApplicationSupport.getBean("tokenStore"); 90 | OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(tokenValue); 91 | return oAuth2AccessToken; 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /oauth2-client/src/main/java/com/company/controller/Oauth2Controller.java: -------------------------------------------------------------------------------- 1 | package com.company.controller; 2 | 3 | 4 | import com.company.utils.ApplicationSupport; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.security.oauth2.client.token.DefaultAccessTokenRequest; 8 | import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsAccessTokenProvider; 9 | import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails; 10 | import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordAccessTokenProvider; 11 | import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails; 12 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 13 | import org.springframework.web.bind.annotation.RequestMapping; 14 | import org.springframework.web.bind.annotation.RequestMethod; 15 | import org.springframework.web.bind.annotation.RequestParam; 16 | import org.springframework.web.bind.annotation.RestController; 17 | 18 | import java.util.Arrays; 19 | 20 | 21 | /** 22 | * @Desc 认证登录接口(获取AccessToken) 23 | */ 24 | @RestController 25 | @RequestMapping("/api/oauth2") 26 | public class Oauth2Controller { 27 | 28 | private static final Logger log = LoggerFactory.getLogger(Oauth2Controller.class); 29 | 30 | /** 31 | * OAuth2的密码授权模式 32 | */ 33 | @RequestMapping(value = "/passwordMode",method = RequestMethod.POST) 34 | public Object accessToken(@RequestParam(value = "client_id") String client_id, 35 | @RequestParam(value = "client_secret") String client_secret, 36 | @RequestParam(value = "grant_type") String grant_type, 37 | @RequestParam(value = "username") String username, 38 | @RequestParam(value = "password") String password 39 | ){ 40 | //补足:对dm5加密后的密码不足32位加零补齐 41 | String fill = ""; 42 | if (password.length() < 32) {//下面的details的password的长度必须32位,所以非32位则,需要补足位数 43 | int len = 32 - password.length(); 44 | fill = String.format("%0" + len + "d", 0); 45 | } 46 | //创建一个包含需要请求的资源实体以及认证信息集合的对象 47 | ResourceOwnerPasswordResourceDetails details = new ResourceOwnerPasswordResourceDetails(); 48 | //设置请求认证授权的服务器的地址 49 | details.setAccessTokenUri(ApplicationSupport.getParamVal("oauth.token")); 50 | //下面都是认证信息:所拥有的权限,认证的客户端,具体的用户 51 | details.setScope(Arrays.asList("read", "write")); 52 | details.setClientId(client_id); 53 | details.setClientSecret(client_secret); 54 | details.setUsername(username); 55 | details.setPassword(fill + password); 56 | 57 | ResourceOwnerPasswordAccessTokenProvider provider = new ResourceOwnerPasswordAccessTokenProvider(); 58 | OAuth2AccessToken accessToken = null; 59 | try { 60 | //获取AccessToken 61 | // 1、(内部流程简介:根据上述信息,将构造一个前文一中的请求头为 "Basic Base64(username:password)" 的http请求 62 | //2、之后将向认证授权服务器的 oauth/oauth_token 端点发送请求,试图获取AccessToken 63 | accessToken = provider.obtainAccessToken(details, new DefaultAccessTokenRequest()); 64 | } catch (NullPointerException e) { 65 | log.error("授权失败原因:{}", e.getMessage()); 66 | return "用户不存在"; 67 | }catch (Exception e){ 68 | log.error("授权失败原因:{}", e.getMessage()); 69 | return "创建token失败"; 70 | } 71 | return accessToken; 72 | } 73 | 74 | /** 75 | * Oauth2的受信任的客户端授权模式 76 | */ 77 | @RequestMapping(value = "/clientMode",method = RequestMethod.POST) 78 | public Object getToken(@RequestParam(value = "client_id") String client_id, 79 | @RequestParam(value = "client_secret") String client_secret, 80 | @RequestParam(value = "grant_type") String grant_type 81 | ){ 82 | //创建一个包含需要请求的资源实体以及认证信息集合的对象 83 | ClientCredentialsResourceDetails clientCredentials = new ClientCredentialsResourceDetails(); 84 | clientCredentials.setAccessTokenUri(ApplicationSupport.getParamVal("oauth.token")); 85 | //下面都是认证信息:所拥有的权限,认证的客户端 86 | clientCredentials.setScope(Arrays.asList("read", "write")); 87 | clientCredentials.setClientId(client_id); 88 | clientCredentials.setClientSecret(client_secret); 89 | clientCredentials.setGrantType(grant_type); 90 | ClientCredentialsAccessTokenProvider provider = new ClientCredentialsAccessTokenProvider(); 91 | OAuth2AccessToken accessToken = null; 92 | try { 93 | accessToken = provider.obtainAccessToken(clientCredentials, new DefaultAccessTokenRequest()); 94 | } catch (Exception e) { 95 | e.printStackTrace(); 96 | return "获取AccessToken失败"; 97 | } 98 | return accessToken; 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /Oauth2学习/流程图/Oauth2认证授权流程图[浏览器打开].svg: -------------------------------------------------------------------------------- 1 | 请求发送者Oauth2请求存储媒介BasicAuthenticationFilterAuthenticationManager:authenticationManager1、doFilter处理请求2、doFilterInternal:调用认证管理器进行的认证DaoAuthenticationProvider调用默认UserDetailsService的实现类ClientDetailsUserDetailsService加载数据,loadUserByUsername,内部调用ClientDetailsService的loadClientByClientIdClientDetailsService使用指定ClientDetailsService的实现类,调用loadClientByClientId方法加载ClientDetails对象,而该接口的实现类有:1、InMemoryClientDetailsService2、JdbcClientDetailsService认证信息存储方式:1、内存2、数据库authenticate(authRequest)loadUserByUsername(username)loadClientByClientId返回ClientDetails与请求数据比较认证成功,继续下个过滤器;认证失败,抛出异常TokenEndpoint认证成功且过滤器链执行完毕,则请求映射到/oauth/token接口,试图获取AccessTokenClientDetailsService1、该接口的实现类有:InMemoryClientDetailsService和JdbcClientDetailsService2、调用loadClientByClientId加载ClientDetails对象TokenGranter抽象类:AbstractTokenGranter不同的子类处理不同的认证请求,并返回AccessToken1、AuthorizationCodeTokenGranter2、ClientCredentialsTokenGranter3、ResourceOwnerPasswordTokenGranter4、ImplicitTokenGranter5、RefreshTokenGranterTokenStore存储方式:1、InMemoryTokenStore2、JdbcTokenStore3、JwtTokenStore4、RedisTokenStoreloadClientClientByClientIdgrant(grantType,tokenRequest)storeAccessToken(accessToken,authentication)返回AccessToken返回AccessToken返回AccessToken认证授权成功,返回AccessToken认证步骤01认证步骤02认证步骤03授权步骤01认证成功授权开始授权步骤02授权步骤03授权步骤04授权结束 --------------------------------------------------------------------------------