本文共 7916 字,大约阅读时间需要 26 分钟。
原文同步至
使用 OAuth 2.0 认证的的好处是显然易见的。你只需要用同一个账号密码,就能在各个网站进行访问,而免去了在每个网站都进行注册的繁琐过程。
本文将介绍 OAuth 2.0 的原理,并基于 Spring Security 和 GitHub 账号,来演示 OAuth 2.0 的认证的过程。OAuth 2.0 的规范可以参考 :
OAuth 是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。目前,OAuth 的最新版本为 2.0
OAuth 允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的网站(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth 允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要分享他们的访问许可或他们数据的所有内容。
OAuth 2.0 主要有4类角色:
认证流程如下:
+--------+ +---------------+ | |--(A)- Authorization Request ->| Resource | | | | Owner | | |<-(B)-- Authorization Grant ---| | | | +---------------+ | | | | +---------------+ | |--(C)-- Authorization Grant -->| Authorization | | Client | | Server | | |<-(D)----- Access Token -------| | | | +---------------+ | | | | +---------------+ | |--(E)----- Access Token ------>| Resource | | | | Server | | |<-(F)--- Protected Resource ---| | +--------+ +---------------+
其中,用户授权有四种模式:
Talk is cheap!下面将演示代码。
本例子将通过 Gradle、Spring Boot、Spring Security、 Thymeleaf、等技术来实现一个client 以及 resource server,并 通过 GitHub来给我们的应用授权。本项目基于Gralde 来管理依赖,读者可以自行改成 Maven 的方式:
// 该依赖对于编译发行是必须的 compile('org.springframework.boot:spring-boot-starter-web') // 添加 Thymeleaf 的依赖 compile('org.springframework.boot:spring-boot-starter-thymeleaf') // 添加 Spring Security 依赖 compile('org.springframework.boot:spring-boot-starter-security') // 添加 Thymeleaf Spring Security 依赖,与 Thymeleaf 版本一致都是 3.x compile('org.thymeleaf.extras:thymeleaf-extras-springsecurity4:3.0.2.RELEASE') // 添加 Spring Security OAuth2 依赖 compile('org.springframework.security.oauth:spring-security-oauth2:2.1.0.RELEASE') // 该依赖对于编译测试是必须的,默认包含编译产品依赖和编译时依 testCompile('org.springframework.boot:spring-boot-starter-test') // 添加 Spring Security Test 依赖 testCompile('org.springframework.security:spring-security-test:4.2.2.RELEASE')
项目的核心配置如下:
github.client.clientId=ad2abbc19b6c5f0ed117github.client.clientSecret=26db88a4dfc34cebaf196e68761c1294ac4ce265github.client.accessTokenUri=https://github.com/login/oauth/access_tokengithub.client.userAuthorizationUri=https://github.com/login/oauth/authorizegithub.client.clientAuthenticationScheme=formgithub.client.tokenName=oauth_tokengithub.client.authenticationScheme=querygithub.resource.userInfoUri=https://api.github.com/user
包括了作为一个client 所需要大部分参数。其中 clientId 、 clientSecret 是在 GitHub 注册一个应用时生成的。如果读者不想注册应用,则可以直接用上面的配置即可。
如果要注册,则文章最后有注册流程。安全配置上需要加上@EnableWebSecurity
、 @EnableOAuth2Client
注解,来启用Web 安全认证记忆,表明这是一个OAuth 2.0 客户端 :
@EnableWebSecurity@EnableOAuth2Client // 启用 OAuth 2.0 客户端 public class SecurityConfig extends WebSecurityConfigurerAdapter {
使用 Spring Security,我们需要继承 org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
并重写以下 configure 方法:
@Overrideprotected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class) .antMatcher("/**") .authorizeRequests() .antMatchers("/", "/index", "/403","/css/**", "/js/**", "/fonts/**").permitAll() // 不设限制,都允许访问 .anyRequest() .authenticated() .and().logout().logoutSuccessUrl("/").permitAll() .and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) ;}
上面的配置是设置了一些过过滤策略,除了静态资源以及不需要授权的页面,我们允许访问,其他的资源,都是需要授权访问。
其中,我们也设置了一个过滤器 ssoFilter,用于在 BasicAuthenticationFilter 之前进行拦截。如果拦截道的是/login
,就是访问认证服务器。
private Filter ssoFilter() { OAuth2ClientAuthenticationProcessingFilter githubFilter = new OAuth2ClientAuthenticationProcessingFilter("/login"); OAuth2RestTemplate githubTemplate = new OAuth2RestTemplate(github(), oauth2ClientContext); githubFilter.setRestTemplate(githubTemplate); UserInfoTokenServices tokenServices = new UserInfoTokenServices(githubResource().getUserInfoUri(), github().getClientId()); tokenServices.setRestTemplate(githubTemplate); githubFilter.setTokenServices(tokenServices); return githubFilter;}@Beanpublic FilterRegistrationBean oauth2ClientFilterRegistration( OAuth2ClientContextFilter filter) { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(filter); registration.setOrder(-100); return registration;}@Bean@ConfigurationProperties("github.client")public AuthorizationCodeResourceDetails github() { return new AuthorizationCodeResourceDetails();}@Bean@ConfigurationProperties("github.resource")public ResourceServerProperties githubResource() { return new ResourceServerProperties();}
我们写了两个控制器来提供相应的资源。
MainController.java
@Controllerpublic class MainController { @GetMapping("/") public String root() { return "redirect:/index"; } @GetMapping("/index") public String index(Principal principal, Model model) { if(principal == null ){ return "index"; } System.out.println(principal.toString()); model.addAttribute("principal", principal); return "index"; } @GetMapping("/403") public String accesssDenied() { return "403"; }}
在index 页面,将如认证成功,将会显示一些认证信息。
UserController.java 是用来模拟用户管理的相关资源。
@RestController@RequestMapping("/")public class UserController { /** * 查询所用用户 * @return */ @GetMapping("/users") @PreAuthorize("hasAuthority('ROLE_USER')") // 指定角色权限才能操作方法 public ModelAndView list(Model model) { Listlist = new ArrayList<>(); // 当前所在页面数据列表 list.add(new User("waylau",29)); list.add(new User("老卫",30)); model.addAttribute("title", "用户管理"); model.addAttribute("userList", list); return new ModelAndView("users/list", "userModel", model); }}
页面,我主要是采用 Thymeleaf 以及Bootstrap 来编写的。
首页用于现实用户的基本信息。
Hello Spring Security
已有用户登录
登录的用户为:
用户权限为:
用户头像为:
未有用户登录
用户管理界面显示用户的列表:
Welcome to waylau.com
Age Name Operation 没有用户信息!! 11 waylau 我是管理员
这个是没有授权访问首页:
当我们点击登录,会重定向到 GitHub,登录界面并进行授权:
这个是授权后的首页:
授权后就能够进入用户管理界面:
如果需要注册,请看下面的流程,来生成 Client ID 和 Client Secret
访问
注册应用,生成 客户端 id 和 密码。比如:
Client ID :ad2abbc19b6c5f0ed117Client Secret :26db88a4dfc34cebaf196e68761c1294ac4ce265
客户端 id 和 密码写入程序配置即可。
转载地址:http://artil.baihongyu.com/