springboot2.x实现oauth2授权码登陆的方法

下面是详细讲解“springboot2.x实现oauth2授权码登陆的方法”的完整攻略:

什么是OAuth2?

OAuth2是目前最流行的用户认证和授权协议之一。它的目的是让用户可以授权第三方应用访问他们的资源,而不必将自己的用户名和密码直接提供给第三方应用。OAuth2协议有多种授权方式,其中最常用的是授权码模式。

OAuth2授权码模式流程

OAuth2授权码模式的流程分为以下步骤:

  1. 用户打开客户端以后,客户端要求用户给予授权,这时候用户会被要求输入用户名和密码。

  2. 客户端拿到用户的用户名和密码,向授权服务器申请令牌。

  3. 授权服务器对客户端进行认证以后,确认无误,同意发放令牌。

  4. 客户端使用令牌,向资源服务器申请资源。

  5. 资源服务器确认令牌无误,同意向客户端开放资源。

详细的授权码模式流程可以参考OAuth2协议的官方文档。

Spring Boot中实现OAuth2授权码登陆的方法

要在Spring Boot中实现OAuth2授权码登陆,需要经过以下步骤:

  1. 添加OAuth2依赖

在pom.xml文件中添加Spring Security OAuth2依赖:

<dependency>
    <groupId>org.springframework.security.oauth</groupId>
    <artifactId>spring-security-oauth2</artifactId>
    <version>2.4.0</version>
</dependency>
  1. 配置OAuth2

在Spring Boot配置文件application.properties中添加以下配置项:

spring.security.oauth2.client.registration.google.client-id=clientId
spring.security.oauth2.client.registration.google.client-secret=clientSecret
spring.security.oauth2.client.registration.google.scope=openid,email,profile
spring.security.oauth2.client.provider.google.authorization-uri=https://accounts.google.com/o/oauth2/v2/auth
spring.security.oauth2.client.provider.google.token-uri=https://www.googleapis.com/oauth2/v4/token
spring.security.oauth2.client.provider.google.user-info-uri=https://www.googleapis.com/oauth2/v3/userinfo
spring.security.oauth2.client.provider.google.user-name-attribute=name

其中,配置项的具体含义可以参考Spring Security OAuth2的官方文档。

  1. 创建授权服务器配置

创建授权服务器配置类,指定OAuth2授权服务器的属性:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private UserDetailsService userDetailsService;

    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource).passwordEncoder(new BCryptPasswordEncoder());
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore())
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService);
    }
}

这里采用JdbcTokenStore,将令牌保存在数据库中。客户端信息也保存在数据库中。

  1. 创建WebSecurityConfigurerAdapter配置

创建WebSecurityConfigurerAdapter配置类,指定安全控制的属性:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(new BCryptPasswordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/login/**","/oauth/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .defaultSuccessURL("/index")
                .permitAll()
                .and()
                .logout()
                .permitAll();
    }
}

这里定义了用于登录验证的UserDetailsService,并设置了一些权限控制。

  1. 创建WebMvcConfigurer配置

创建WebMvcConfigurer配置类,指定URL的处理方式:

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/login").setViewName("login");
    }
}

这里指定URL “/login” 的视图为“login”。

  1. 创建视图

创建登录页面视图“login.html”:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login Page</title>
</head>
<body>
    <form th:action="@{/oauth/authorize}" method="post">
        <div>
            <label>Username:</label>
            <input type="text" id="username" name="username" required="required"/>
        </div>
        <div>
            <label>Password:</label>
            <input type="password" id="password" name="password" required="required"/>
        </div>
        <div>
            <input type="submit" value="Log In"/>
        </div>
    </form>
</body>
</html>
  1. 创建ResourceServerConfigurerAdapter配置

创建ResourceServerConfigurerAdapter配置类,指定需要保护的资源:

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers(HttpMethod.GET,"/api/**").access("#oauth2.hasScope('read')")
                .antMatchers(HttpMethod.POST,"/api/**").access("#oauth2.hasScope('write') and hasRole('ROLE_ADMIN')")
                .antMatchers(HttpMethod.PUT,"/api/**").access("#oauth2.hasScope('write') and hasRole('ROLE_ADMIN')")
                .antMatchers(HttpMethod.DELETE,"/api/**").access("#oauth2.hasScope('write') and hasRole('ROLE_ADMIN')");
    }
}

这里指定了需要保护的资源,通过OAuth2授权进行访问。

至此,我们已经完成了OAuth2授权码登陆的配置。

示例

下面提供两条示例:

示例1

我们可以通过Google OAuth2服务进行认证。打开浏览器,输入地址http://localhost:8080/oauth/authorize?response_type=code&client_id=clientId&redirect_uri=https://www.baidu.com/,回车,系统会跳转到Google OAuth2服务的认证页面。输入Google账号和密码,授权成功后系统会重定向到 https://www.baidu.com/?code=authCode,其中authCode是授权码。

在获得授权码后,我们可以通过POST请求获取访问令牌:

POST /oauth/token HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded
Authorization: Basic Y2xpZW50SWQ6Y2xpZW50U2VjcmV0
Cache-Control: no-cache

grant_type=authorization_code&code=authCode&redirect_uri=https://www.baidu.com/

其中,Y2xpZW50SWQ6Y2xpZW50U2VjcmV0 是client ID和client secret经过Base64编码后的结果,authCode是前面获得的授权码,redirect_uri是我们前面指定的重定向地址。

POST请求的返回内容如下:

{
   "access_token":"accessToken",
   "token_type":"bearer",
   "refresh_token":"refreshToken",
   "expires_in":3599,
   "scope":"openid email profile"
}

其中,accessToken是访问令牌,refreshToken是用于重新申请访问令牌的令牌,expires_in是访问令牌的过期时间(单位为秒),scope是访问令牌的范围。

我们可以使用下面的GET请求,使用访问令牌访问受保护的资源:

GET /api/hello HTTP/1.1
Host: localhost:8080
Content-Type: application/json
Authorization: Bearer accessToken

其中,访问令牌要放在Authorization头中,Bearer是OAuth2指定的身份验证方案。

如果访问令牌有效,则会返回以下JSON格式数据:

{
   "message":"Hello World!"
}

示例2

我们可以在应用程序的login视图中添加一个连接,指向http://localhost:8080/oauth/authorize。用户点击这个链接后,会跳转到OAuth2授权服务器的认证页面,进行用户认证和授权。授权完成后,系统会跳转回应用程序,并根据用户角色显示相应的页面。

首先,在应用程序的login视图中添加以下连接:

<a href="/oauth/authorize?response_type=code&client_id=clientId&redirect_uri=http://localhost:8080/login/oauth2/code/google">Login with Google</a>

其中,client_id是我们在Google Developer Console中创建应用程序时生成的客户端ID,redirect_uri是重定向地址,可以在Google Developer Console中指定。

然后,在应用程序的Controller中添加以下请求处理方法:

@GetMapping("/login/oauth2/code/google")
public String googleLogin(@RequestParam String code, Authentication authentication, Model model) {
    OAuth2AccessToken accessToken = oAuth2AuthorizedClientService.loadAuthorizedClient("google", authentication.getName()).getAccessToken();
    HttpHeaders headers = new HttpHeaders();
    headers.setBearerAuth(accessToken.getTokenValue());
    HttpEntity<?> entity = new HttpEntity<>(headers);
    ResponseEntity<GoogleUserInfo> response = restTemplate.exchange("https://www.googleapis.com/oauth2/v2/userinfo", HttpMethod.GET, entity, GoogleUserInfo.class);
    GoogleUserInfo userInfo = response.getBody();
    if (userInfo != null) {
        if (userRepository.findByEmail(userInfo.getEmail()) == null) {
            User user = new User();
            user.setEmail(userInfo.getEmail());
            user.setUsername(userInfo.getName());
            user.setRoles(Collections.singleton("ROLE_USER"));
            userRepository.save(user);
        }
    }
    User user = userRepository.findByEmail(userInfo.getEmail());
    model.addAttribute("user", user);
    return "index";
}

其中,我们使用OAuth2AuthorizedClientService从授权服务器请求访问令牌,使用RestTemplate访问资源服务器的API获得用户信息,通过userRepository保存用户信息,最后将用户信息添加到视图。

下面是GoogleUserInfo的实现:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class GoogleUserInfo {

    private String id;

    private String email;

    private String name;

}

最后,在应用程序的控制器中添加以下授权检查逻辑:

@GetMapping("/api/hello")
public Map<String, String> hello(Authentication authentication) {
    OAuth2Authentication oauth = (OAuth2Authentication) authentication;
    Map<String, String> map = new HashMap<>();
    map.put("message", "Hello World! You have " + oauth.getAuthorities().toString());
    return map;
}

其中,oauth.getAuthorities()可以获取用户的角色信息。

至此,我们完成了使用Google OAuth2服务进行OAuth2授权码登陆的过程。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:springboot2.x实现oauth2授权码登陆的方法 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • Java自动化工具Ant的基础使用教程

    Java自动化工具Ant的基础使用教程 简介 Ant(Another Neat Tool)是一个基于Java开发的构建工具,它是基于脚本的、可扩展的构建系统。Ant通过XML文件来进行构建,而无需使用特定的编程语言来编写构建逻辑。Ant可以自动编译Java代码,运行Junit测试,生成Java文档等。 基础使用 安装 下载Ant安装程序,官方下载地址为:ht…

    Java 2023年5月26日
    00
  • SpringBoot项目访问任意接口出现401错误的解决方案

    当我们使用SpringBoot项目访问任意接口时出现401错误,可能是因为项目的权限配置问题导致的。下面是解决它的完整攻略: 1.检查接口权限 首先我们需要检查接口权限,确定是否已经在项目中配置了相应的权限。我们可以通过查看Spring Security配置文件(一般为SecurityConfig.java)的代码或者在SpringBoot Admin管理后…

    Java 2023年5月20日
    00
  • jQuery实现遍历XML节点和属性的方法示例

    下面是jQuery实现遍历XML节点和属性的方法示例的详细攻略。 1. 准备XML数据 首先,需要准备一份XML格式的数据。如果手头没有可以使用的XML数据,可以自己创建一个XML文件。 <?xml version= "1.0" encoding= "UTF-8"?> <bookstore> &…

    Java 2023年5月19日
    00
  • java编译器和JVM的区别

    Java编译器和JVM(Java虚拟机)是Java语言的两个核心组成部分,它们分别承担着Java程序的编译和执行任务。下面将详细讲解它们的区别: Java编译器 Java编译器是负责把Java源代码(.java)编译成Java字节码(.class)的工具。在Java的编译过程中,Java编译器会将源代码解析成对应的抽象语法树,然后将抽象语法树翻译成字节码,最…

    Java 2023年5月26日
    00
  • Mybatis入门教程之新增、更新、删除功能

    下面是针对“Mybatis入门教程之新增、更新、删除功能”的详细攻略。 1. 简介 Mybatis是一款优秀的持久层框架,它对JDBC进行了很好的封装,简化了JDBC的操作流程,使得我们可以更方便的操作数据库。其中,新增、更新和删除等功能是常见的操作,也是我们使用Mybatis进行开发时必须掌握的内容。 2. 新增功能 新增功能可以通过Mybatis提供的i…

    Java 2023年5月20日
    00
  • MyBatis还是JPA?终于有答案了

    我们来详细讲解“MyBatis还是JPA?终于有答案了”的完整攻略。 1. 背景介绍 在进行Java Web开发时,ORM框架是不可或缺的工具之一,其可以将Java对象映射到关系型数据库中。MyBatis和JPA是流行的ORM框架,那么如何选择呢? 2. MyBatis和JPA区别 2.1 MyBatis MyBatis是基于SQL语句的ORM框架,其与关系…

    Java 2023年5月19日
    00
  • Java实现文件的分割与合并

    下面是详细的讲解: 1.需求分析 在很多情况下,我们需要将大文件拆分成多个小文件进行存储或传输。因此需要实现一个文件分割与合并的工具。Java提供的File类可以很好地操作文件,但并不提供文件分割和合并的功能。下面我们就来讲讲如何在Java中实现文件分割与合并。 2.文件分割 文件分割就是将一个大文件切割成若干个小文件,方便存储和传输。Java中实现文件分割…

    Java 2023年5月20日
    00
  • JDBC连接SQL Server数据库实现增删改查的全过程

    JDBC(Java DataBase Connectivity)是Java语言中连接数据库进行操作的一种标准规范。下面是连接SQL Server数据库实现增删改查的全过程: 准备工作 安装SQL Server数据库,获取数据库的连接配置信息,包括地址、用户名、密码、端口等信息。 下载并安装SQL Server JDBC驱动,下载地址:https://docs…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部