Spring Boot+OAuth2单点登录

一. 搭建统一认证中心 (port:1111)
1.1 引入依赖

在这里插入图片描述

1.2 资源服务器

项目创建成功之后,这个模块由于要扮演授权服务器+资源服务器的角色,所以我们先在这个项目的启动类上添加 @EnableResourceServer 注解,表示这是一个资源服务器:

@SpringBootApplication
@EnableResourceServer
public class AuthServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(AuthServerApplication.class, args);
    }

}
1.3 授权服务器

接下来我们进行授权服务器的配置,由于资源服务器和授权服务器合并在一起,因此授权服务器的配置要省事很多:

@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    PasswordEncoder passwordEncoder;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("javaboy")
                .secret(passwordEncoder.encode("123"))
                .autoApprove(true)
                .redirectUris("http://localhost:1112/login", "http://localhost:1113/login")
                .scopes("user")
                .accessTokenValiditySeconds(7200)
                .authorizedGrantTypes("authorization_code");

    }
}
1.4 配置Spring Security 用户信息
package com.cicro.oauth_sso.sso_auth_resource_server.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@Order(1)  //因为资源服务器和授权服务器在一起,所以我们需要一个 @Order 注解来提升 Spring Security 配置的优先级。
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 静态资源放行
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/login.html", "/css/**", "/js/**", "/images/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.requestMatchers()
            .antMatchers("/login")//认证的相关接口放行
            .antMatchers("/oauth/authorize")
            .and()
            .authorizeRequests().anyRequest().authenticated()
            .and()
            .formLogin()
            .loginPage("/login.html")//登录页面和登录接口
            .loginProcessingUrl("/login")
            .and().logout()
            .permitAll()
            .and()
            .csrf().disable();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("sang")
            .password(passwordEncoder().encode("123"))
            .roles("admin");
    }
}

1.5 提供暴露用户信息的接口
@RestController
public class UserController {
    @GetMapping("/user")
    public Principal getCurrentUser(Principal principal) {
        return principal;
    }
}

如果是资源服务器和授权服务器分开的,这个接口就由资源服务器提供

1.6 提供登录页面

在static目录下编写login.html登录测试页面

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>统一认证中心</title>
</head>
<body>
<form action="/login" method="post">
  <div class="input">
    <label for="name">用户名</label>
    <input type="text" name="username" id="name">
    <span class="spin"></span>
  </div>
  <div class="input">
    <label for="pass">密码</label>
    <input type="password" name="password" id="pass">
    <span class="spin"></span>
  </div>
  <div class="button login">
    <button type="submit">
      <span>登录</span>
      <i class="fa fa-check"></i>
    </button>
  </div>
</form>
</body>
</html>
二. 搭建2个相同的客户端 (port:1112 port:1113)
2.1 引入依赖

在这里插入图片描述

2.2 配置SecurityConfig
@Configuration
@EnableOAuth2Sso  //开启单点登录功能
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated().and().csrf().disable();
    }
}
2.3 提供测试接口
@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return authentication.getName() + Arrays.toString(authentication.getAuthorities().toArray());
    }
}
2.4 配置
#客户端密钥
security.oauth2.client.client-secret=123
#客户端client-id
security.oauth2.client.client-id=javaboy
#用户授权的端点
security.oauth2.client.user-authorization-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=1113
#取个名字
server.servlet.session.cookie.name=s2
2.5 测试

登录后访问1112端口正常,之后在访问1113不用登录直接能访问了

三. 流程解析
  1. 首先我们去访问 client1 的 /hello 接口,但是这个接口是需要登录才能访问的,因此我们的请求被拦截下来,拦截下来之后,系统会给我们重定向到 client1 的 /login 接口,这是让我们去登录。
    在这里插入图片描述

  2. 当我们去访问 client1 的登录接口时,由于我们配置了 @EnableOAuth2Sso 注解,这个操作会再次被拦截下来,单点登录拦截器会根据我们在 application.properties 中的配置,自动发起请求去获取授权码:
    在这里插入图片描述

  3. 在第二步发送的请求是请求 auth-server 服务上的东西,这次请求当然也避免不了要先登录,所以再次重定向到 auth-server 的登录页面,也就是大家看到的统一认证中心。

  4. 在统一认真中心我们完成登录功能,登录完成之后,会继续执行第二步的请求,这个时候就可以成功获取到授权码了。
    5.

  5. 获取到授权码之后,这个时候会重定向到我们 client1 的 login 页面,但是实际上我们的 client1 其实是没有登录页面的,所以这个操作依然会被拦截,此时拦截到的地址包含有授权码,拿着授权码,在 OAuth2ClientAuthenticationProcessingFilter 类中向 auth-server 发起请求,就能拿到 access_token 了

  6. 在第五步拿到 access_token 之后,接下来在向我们配置的 user-info-uri 地址发送请求,获取登录用户信息,拿到用户信息之后,在 client1 上自己再走一遍 Spring Security 登录流程,这就 OK 了。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值