Spring Boot+OAuth2,一个注解搞定单点登录!


需求先说一下,松哥最近写的教程,都是成系列的,有一些重复的东西写来写去就没意思了,所以每一篇文章都默许我们现已懂了前面的内容了,因此下文有任何看不理解的当地,建议一定先看下相关系列:

Spring Security 系列:

  1. 挖一个大坑,Spring Security 开搞] 8 U P
  2. 松哥手把手带你入门 Spring Security,别再问暗码怎样解密了
  3. 手把手教你定制 Spring Security 中的表单登录
  4. Spring Security 做前后端分别,咱就别做页面跳转了!统统 JSON 交互
  5. Spring Security 中的授权操作本来= n h这么简略
  6. Spring Security 如何将用户数据存入数据库?
  7. Spring Security+SY | Spring Data Jpa 强强联手,安全办理只^ m 4 t n q V v $有更简略!

OAuth2 系列:

  1. 做微服务绕不过的 OAuth2,松| 4 )哥也来和我们扯一扯
  2. 这个案例写出来,还怕跟面试官扯不理解 OAuth2 登录流程?
  3. P ? T磕 OAuth2,教练我要学全套的!
  4. OAuth2 令牌还能存入 Redis ?越玩越溜!
  5. 想让 OAuth2 和 Jf | , } ( q ZWT 在一同愉快玩耍?请看松哥的扮演
  6. 和我们共享一点微服务架构中的安全办理思路

好了,初步今天的正文。

单点登录是我们在分布式系统中很常见的一个需求。

分布式系统由多个不同的子系统组成,而我们在运用系统的时分,只需求登录一次即可,这样其他系统都认为用户现已登录了,不必再去登录。前面和小伙伴们共享了 OAF ( O Euth2+JWT 的登录办法,这种无状况登录实际上天然的满意单点登录的需求,可以参看:想让 OAuth2 和 JWT 在一同愉快玩耍?请看松哥的扮演。

A ; p v A然我们也都知道,u y 7 t G A *无状况登录也是有害处的。

所以今天松哥想和我们说一说 Spring Boot+OAuth2 做单点登录,使用 @EnableOAuth2Sso 注解快速完成单点登录功用。

松哥依然建议我们在阅览本文时,先看看本= _ ^系列前面的文章,这有助于更好的理解W R P @本文。

1.项目创建

前面的案例中,松哥一直都把授权服务器和资源服务器分隔创建,6 / ` @ n Z w今天这个案例,为了省劲,我就把授权服务器和资源服务器建立在一同(a 5 l不过相信我们看了前面的文章,应该也能自己把这两? I O个服务器拆分隔)。

所以,今天我们一共需求三个服务:

项目 端口 描绘
auth-server 1111 授权服务器+资源服务器
client1 1112 子系统1
cZ p F ^ B 0 * ! Zlient2 1113 子系统2

auth-server 用来扮演授权服务器+资源服务器的角色,client1 和 client2 则分别扮演子系统的角色,将来等 client1 登录成功Y M * R )之后,我们也就能访问 client2 了,这样就能看出来单点登录的效果。

我们创建一个名为 oauth2-sso 的 Maven 项目作为父工程即可。

2.共同认证中心

接下来我们来建立共同认证中心。

首要我们创建一个名为 auth-server 的 module,创建时增加如下依靠:

Spring Boot+OAuth2,一个注解搞定单点登录!

项目创建d } T / M # a 6 ,成功之后,这个模块因为要扮演授权服务器* h ] y M+资源服务t [ ) e E % U E i器的角色,所以我们先在这个项目的发动类上增4 x } 0 D ? 1 b u加 @EnableResourceServer 注解,表明这是一个资源服务器:

@SpringBootApplication
@EnableResourceServer
public class AuthServerAh H Spplication {
public static void main(String[] args) {
Spj w x D l ; & U cringApplication.4 t : T ` T trun(AuthServerApplis Y m rcation.class, arg. q d u T 1 ? ks j 2 R);
}
}

接下来我们进行授权服务器的配备,因为资源服务器和授权服务器吞并在一同,N [ _ ?因此授权服务器的配备要省劲许多:

@Configuration
@EnableAuthorizationServer
public$ Q ) ] w ^ class AuthServerConfig extendsW Y Q ? _ d W @ W AuthorizationSe2 1 ~ X f ] X t frverConfigurerAdapter {
@Autowired
PasswordEncoder passwordEncoder;
@Override
publiY x c 9c void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("javaboy")
.secret(passwordEncoder.encode("123"))
.autoApprove(true)
.redirectUris("httU y ( Fp://loca2 N E Llhost:1112/login", "http://localhost:1113/logb m ) 5 v m = !in")
.scopes("user")
.accessTokenValiditySeconO . 5 N S o $ {ds(9 , M K7200)
.authorizedGrantTypes("authorization_code"i : l F m B K *);
}
}

这儿我们只需求简略配备一下客户端的信息即可,这儿的配备很简略,前面的文章也讲过了,我们要是不理解,可以参看本系列前面的文章:这个案例写出= } F } –来,还怕跟面试官扯不理解 OAuth2d x ] P f 7 7 w 登录流程?。

当然这儿为了简洁,客户端2 M _ m M 4的信息配备是根据内存的,假设 N Q 5 ,我们想将} b 7 z客户端信息存入数据库中,也是可以的,参看:OAuth2 令牌还能存入 Redis ?越玩越溜!

接下来我们再来配备 Spring Security:

@Configuration
@Ordew - B rr(1)
public class SecurityConfB ] ] L X 5 , Mig extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptP) Q ) k ~ 0 #asswordEncoder();
}
@Override
public void configure(WebSecurity web) throws Exp E E v rception {
web.ignoring().antMatchers("/login.html", "/css/**", "/js/**", "/7 : v M W { [images/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()= i s
.antMatchers("/login")
.antMatchers("/oauth/authorize")
.and()
.authorE G } b |izeRequests().anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/login")
.permitAll()
.and()
.csrf().disable();
}
@OA # x 1 ^ n Nvev w )rride
protected void configure(AuthenticationZ M l ManagerBuilder auth) throws Exception {
auth.inMemoryAuthentm 3 w D ( 1 3ication()
.withUser("sang")
.passy F C { u  @word(passwordEncoder().encode("123r b W o T -"))
.roles("admin");
}
}

关于 Spring Security 的配备,假设小伙伴们不理解,可以看看松哥最近正在连载的 Spring Securiu k [ p 8 ty 系列。

我这儿来大致捋一下:

  1. 首要供应一个 BCryptPasswordEI ] ; X . L %ncoder 的实) u /例,用来做暗码加解密用。
  2. 因为我自定义了登录页面,所以在 WebSecurity 中对这些静态资源方形。
  3. HttpSecurity 中,咱t 7 . % ~ n {们对认证相关的端点放行,一同配备一下登录页面和登录接口。
  4. AuthenticationManag~ ] c MerBuilder 中供应一个根据内存的用户(小伙伴们可以根据 Spring Security 系列第 7 篇文章自行调整为从数据库加载)。
  5. 其他还有一个比较关键的当地,因为资源服务器和授权服务器在一同,所以我们需求一个 @Order 注解来提升 Spring Security 配备的优+ L !先级。

SecurityConfig 和 Aut3 X x ; : e EhServerConfig 都是~ V s d A D授权服务器需求供应的东西(假设小伙伴们想将授权服务器和资源服U ? _务器拆分,请留意这句话),接下来,我们还需求供应一个露出用户信息的d C L 1 @接口(假设将授权服务器和资源服务器分隔,这个接口将由资源服务器供应):

@RestController
public class UserController {
@GetMapping("/user")
public Principal getCurrentUser(Principal principZ V A ;al) {
return principal;
}
}

终究,我们在 application.properties 中! + | x M o S `配备一下项目端口:

server.port=1111

其他,松哥自己提前准备了一个登录页面,如下:

Spring Boot+OAuth2,一个注解搞定单点登录!

将登录页面相关的 ht@ [ 5ml、css、js 等1 R ? c I 9 { / 1拷贝到 resources/static 目录下:

Spring Boot+OAuth2,一个注解搞定单点登录!

这个页面很简略,R V v R m就是一个登录表单罢了,我把核心部分列出来:

<form action="/login" method="postz 4 U _ 5 f | C">
<div class="i1 $ l 9 e 6 $ hnput">
<label for="name"&t . $gt;用户名</label>
<input type="text" name="username" id="name">
<span class="spin"></span>
</div>
<div class="input">
&3 w g * 0 Q 2 qlt;f 4 n S h B { 0 vlabel for="pass">暗码</label>
<input type="password" name="password" id="pass">
<spa& P O 0 p c  X Qn cla& f } - ! rss="spin">&S ; [ slt;/span>
</div>
<div class="button login">
<button type="submit">
<span! w E 3 9 h *>登录</span>
<i clA G d 0 0 7ass="fa fa-check"></i>
</button>
</div>
&ltV D g , 5 P | T M;/form>

留意一下 acti? 0 z Won 提交地址不要写错即可。

文末可以下E p r A Xs k g ! s源码。

如此之后,我们的共同认证登录平台就算是 OK 了。

3.客户端创建

c Q @ = A ; H /下来我们来创建一个客户端项目,创建一个名为 client1 的 Spring Boo] ] 0 E [ y B 9t 项目,增加如下依靠:

Spring Boot+OAuth2,一个注解搞定单点登录!

项目创建成功之后,我们来配备一下 Spring Security:

@Configuratio4 S u | ] Kn
@EnableOAuth2Sso
public class Sei L ( vcurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequeu w S Est().authenticated().and().csrf().dR = r ) ]isable();
}
}

这段配备很简略,就是说我们 client1 中所有k 2 ; X s 2 6 Y 2的接口都需求认证之后才干访问,其他增加一个 @EnableOAuth2Sso 注解来敞开单点登录功用。

接下来我们在 client1 中再来供应一个检验接口:

@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return authentication.g7 _ 5 P 6ed 6 t utName() + Arrays.toString(authentication.getAuthorities().toArray());
}
}

这个检验接口返回当时登录用户的名字和角色信息。

接下来我们需求在 client1 的 application.properties 中配备 oauth2 的相关信息:

security.oauth2.client.client-secret=123
security.oauth2.client.client-id=javaboy
security.oauth2.client.user-s i R 6 ; 1 v Kauthorization-uri=http://localhost:1111/oauth/authorize
security.oauth2.client.access-token-uri=http://localhost:1111/oauth/token
security.oauth2.resource.user-info-uri=http://localhost:1111/user
server.port=1112
server.servlet.session.cookie.name=s1

这儿的配备也比较了解,我们来看一下:

  1. client-secret 是客户y S 4 L 3 . M z端暗码。
  2. client-id 是客户端 id。
  3. user-authoO $ X X . 2 prization-uri 是用户授权的端点。
  4. access-token-uri 是获取令牌的端点。
  5. user? : 3 U / *-info-uri 是获取用户信息的接口(q 4 D n ! y d从资源服务器/ G o 7 = [ L上获取)。
  6. 终究再配备一下端口,然后给 cookie 取一个名字。

如此之后,我们的 client1 就算是配备完结了。

e c V – ] l v ! /照相同的办法,7 F #我们再来8 ; R J $ O ` O S配备一个 client2,client2 和 client1 如出一辙,就是s W u c y c cookie 的名字不同(随意取,不相同即可)。

4.检验

接下来,我们分别发动 auth-server、client1 和 client2,首要我们尝试去办法 client1 中的 hello 接口,这个时分会自动跳转到共同认证中心:

Spring Boot+OAuth2,一个注解搞定单点登录!

然后输入N z 2j ` i户名暗码进行登录。

登录成功之后,会自动跳转回 client1 的 hep u $ f o * illo 接口,如下:

Spring Boot+OAuth2,一个注解搞定单点登录!

此时我们再去访问 client2 ,发现也不必登录了,直接就可以访问:

Spring Boot+OAuth2,一个注解搞定单点登录!

OK,如此之后,我们的单点登录就成功了。

5.流W # G程解析

终究,我再来和小伙伴们把上面代码的一个实行流程捋一捋:

  1. 首要我们去访问 client1 的 /hello 接口,可是这个接口是需求登录才干访问的,因此我们的央求被阻挠下来,阻挠下来之后,系统会给我们重定向到 client1 的 /login 接口,这是让我们去登录。
Spring Boot+OAuth2,一个注解搞定单点登录!
  1. 当我们去访问 client1 的登录接口时,因为我们配备了 @EnableOAuth2Sso 注解,这个操作会再次被阻挠下来,单点登录阻挠器会根据我们在 application.properties 中的配备,自动建议央求去获取授权码:
Spring Boot+OAuth2,一个注解搞定单点登录!
  1. 在第二步发送的5 5 r H R @ J }央求是央求 auth-server8 M P E 5 ? [ 服务上的东西,这次央求当然也避免不了要先登录,所以再次重定向到 auth-server 的登C F Q } E _录页面,也就是我们看到的共同认证中心。
  2. 在共同仔细中心我们完结登录功用,登录完结之后, 5 t a会持续实行第二步的央求,这个时分就可以成功获取到@ D T c 5 Y p授权码了。
Spring Boot+OAuth2,一个注解搞定单点登录!
  1. 获取到授权码之后,7 ( r I这个时分( U N j 8 *会重定向j A u L (到我们 client1 的 login 页面,可是实际上我们的 client1 其实是没有登录页面的,所以这个操作依然会被阻挠,此时阻挠到的地址包括有授权码,拿着授权码,在 OAuth2ClientAuthenticationProcessingFilter 类中向w i 5 auth-server 建议] K l央求,就能拿到 access_token 了(参看:这个案例写出来C 6 J g 6,还怕跟面试官扯不理解 OAuth2 登录流程q X w 8?)。
  2. 在第五步拿到 access_tC g ` n + CokenS A P 之后,接下来在) 7 ; E 8 U向我们配备的 user-info-uri 地址发送央求,获取登录用户信息,拿到用Z D q g M户信息之后,在 client1 上自己再走一遍 Spring Sk D . ; z oecurity 登录流程,这就 OK 了。

OK,本文和小伙伴们聊了一些 SpringBoot +OAuth2 单点登录的问题,完整案例下载地址:github.com/lenve/oauth…

假设J C Q F ~ K小伙伴们觉得有用的话,记得点个在看鼓动下松哥。

发表评论

提供最优质的资源集合

立即查看 了解详情