• 【Spring-Security】Re10 Oauth2协议 P1 授权码模式 & 密码模式


    一、Oauth2协议:

    第三方登录,即忘记本站密码,但是登录界面中提供了一些第三方登录,例如微信、支付宝、QQ、等等,通过第三方授权实现登录

    第三方认证技术主要解决的时认证标准,各个平台的登录要遵循统一的接口协议

    所以这里采用的方案是Oauth2

    资料参考:

    https://www.jianshu.com/p/84a4b4a1e833

    二、Spring-Security + Oauth2 环境搭建

    创建一个空的SpringBoot项目:

    删除不必要的文件

    导入POM依赖坐标:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.3.4.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>cn.zeal4j</groupId>
        <artifactId>so2</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>so2</name>
        <description>Spring-Security + Oauth2 project for Spring Boot</description>
    
        <properties>
            <java.version>1.8</java.version>
            <spring-cloud.version>Greenwich.SR2</spring-cloud.version>
        </properties>
    
        <dependencies>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-oauth2</artifactId>
                <!--<version>2.2.4.RELEASE</version>-->
            </dependency>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-security</artifactId>
                <!--<version>2.2.4.RELEASE</version>-->
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud.version}</version><!--<version>Greenwich.SR2</version>-->
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>

    用户实体类:

    package cn.zeal4j.domain;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.userdetails.UserDetails;
    
    import java.util.Collection;
    
    /**
     * @author Administrator
     * @file Spring-Security + Oauth2
     * @create 2020 09 29 11:37
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User implements UserDetails {
        private String username;
        private String password;
        private Collection<GrantedAuthority> authorities;
    
    
        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            return null;
        }
    
        @Override
        public String getPassword() {
            return null;
        }
    
        @Override
        public String getUsername() {
            return null;
        }
    
        @Override
        public boolean isAccountNonExpired() {
            return false;
        }
    
        @Override
        public boolean isAccountNonLocked() {
            return false;
        }
    
        @Override
        public boolean isCredentialsNonExpired() {
            return false;
        }
    
        @Override
        public boolean isEnabled() {
            return false;
        }
    }

    Security安全配置:

    package cn.zeal4j.configuration;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    /**
     * @author Administrator
     * @file Spring-Security + Oauth2
     * @create 2020 09 29 11:35
     */
    @Configuration
    @EnableWebSecurity
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
        @Bean
        public PasswordEncoder getPasswordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        @Override
        protected void configure(HttpSecurity httpSecurity) throws Exception {
            // csrf
            httpSecurity.csrf().disable();
    
            // 登录,退出,授权放行
            httpSecurity.authorizeRequests().antMatchers("/login/**","/logout/**","/oauth/**/").permitAll();
    
            // 允许表单登录
            httpSecurity.formLogin().permitAll();
    
            // 其余请求权限拦截
            httpSecurity.authorizeRequests().anyRequest().authenticated();
        }
    }

    授权服务配置:

    package cn.zeal4j.configuration;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
    import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
    import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
    
    /**
     * @author Administrator
     * @file Spring-Security + Oauth2
     * @create 2020 09 29 11:48
     * @description 授权服务器配置
     */
    @Configuration
    @EnableAuthorizationServer
    public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
    
        @Autowired
        private PasswordEncoder passwordEncoder;
    
        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.
                    inMemory().
                    withClient("admin").
                    secret(passwordEncoder.encode("112233")).
                    accessTokenValiditySeconds(3600). // 令牌有效时间 一小时
                    redirectUris("http://www.baidu.com"). // 授权成功的跳转
                    scopes("all").  // 所有范围
                    authorizedGrantTypes("authorization_code");     // 授权类型:授权码模式
        }
    }

    资源服务配置:

    package cn.zeal4j.configuration;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
    import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
    
    /**
     * @author Administrator
     * @file Spring-Security + Oauth2
     * @create 2020 09 29 11:57
     */
    
    @Configuration
    @EnableResourceServer
    public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
    
        @Override
        public void configure(HttpSecurity httpSecurity) throws Exception {
    
            httpSecurity.authorizeRequests().
                    anyRequest().authenticated(). // 默认任何请求都需要授权
                    and().
                    requestMatchers().antMatchers("/user/**"); // 资源匹配规则
        }
    }

    登录逻辑:

    package cn.zeal4j.service.impl;
    
    import cn.zeal4j.domain.User;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.authority.AuthorityUtils;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    /**
     * @author Administrator
     * @file Spring-Security + Oauth2
     * @create 2020 09 29 11:35
     */
    @Service public class CustomUserDetailsServiceImpl implements UserDetailsService { @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { String encode = passwordEncoder.encode("123456"); return new User("admin", encode, AuthorityUtils.commaSeparatedStringToAuthorityList("admin")); } }

    User资源控制器:

    package cn.zeal4j.controller;
    
    import org.springframework.security.core.Authentication;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    /**
     * @author Administrator
     * @file Spring-Security + Oauth2
     * @create 2020 09 29 12:01
     */
    @Controller
    @RequestMapping("user")
    public class UserController {
    
        /**
         * 获取当前用户
         * @param authentication
         * @return user/getCurrentUser
         */
        @RequestMapping("/getCurrentUser")
        @ResponseBody
        public Object getCurrentUser(Authentication authentication) {
            return authentication.getPrincipal();
        }
    
    }

    启动访问发现:

    二、授权码模式实现:

    发现生成的UserDetails实例默认设置的都是False,SpringSecurity一经权限判断,直接触发拦截

    所以默认这里都要改成TRUE放行通过

        @Override
        public String getPassword() {
            return password;
        }
    
        @Override
        public String getUsername() {
            return username;
        }
    
        @Override
        public boolean isAccountNonExpired() {
            return true;
        }
    
        @Override
        public boolean isAccountNonLocked() {
            return true;
        }
    
        @Override
        public boolean isCredentialsNonExpired() {
            return true;
        }
    
        @Override
        public boolean isEnabled() {
            return true;
        }

    再次测试Oauth2地址:

    http://localhost:8080/oauth/authorize?response_type=code&client_id=admin&redirect_uri=http://www.baidu.com&scope=all

    点击选择Approve允许,点击Authorize进行授权

    https://www.baidu.com/?code=G6ocWn

    这个code就是我们的授权码

    现在使用Postman进行测试:

     1、先选择认证账号信息输入:

    2、然后输入请求参数:

    grant_type    authorization_code
    code             你得到的授权码
    cient_id        admin 
    redirect_uri   http://www.baidu.com
    scope            all

    请求成功则会返回这个消息JSON

    {
        "access_token": "4c562cc7-07c4-47b6-9a5b-537c4f4079cd",
        "token_type": "bearer",
        "expires_in": 43199,
        "scope": "all"
    }

    得到了许可Token

    接着用Token访问资源获取接口:

    http://localhost:8080/user/getCurrentUser

    得到我们返回的数据:

    {
        "username": "admin",
        "password": "$2a$10$tBlHK4KbNFsE7F7usl6AsODWWBkF4oS8Ak4qkaNbEFAsKykvXgH9i",
        "authorities": [
            {
                "authority": "admin"
            }
        ],
        "enabled": true,
        "accountNonLocked": true,
        "credentialsNonExpired": true,
        "accountNonExpired": true
    }

    如果令牌是错误的

    {
        "error": "invalid_token",
        "error_description": "Invalid access token: 2287c3ab-3dc5-475e-97eb-bdffb2a78b8A"
    }

    三、密码模式授权实现:

    package cn.zeal4j.configuration;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
    import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
    import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
    import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
    
    /**
     * @author Administrator
     * @file Spring-Security + Oauth2
     * @create 2020 09 29 11:48
     * @description 授权服务器配置
     */
    @Configuration
    @EnableAuthorizationServer
    public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
    
        @Autowired
        private PasswordEncoder passwordEncoder;
        
        @Autowired
        private AuthenticationManager authenticationManager;
        @Qualifier("customUserDetailsServiceImpl")
        @Autowired
        private UserDetailsService userDetailsService;
    
        /**
         * 使用密码模式需要的配置方法
         * @param endpoints
         * @throws Exception
         */
        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints.
                    authenticationManager(authenticationManager).
                    userDetailsService(userDetailsService);
        }
    
        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.
                    inMemory().
                    withClient("admin").
                    secret(passwordEncoder.encode("112233")).
                    // accessTokenValiditySeconds(3600). // 令牌有效时间 一小时
                    redirectUris("http://www.baidu.com"). // 授权成功的跳转
                    scopes("all").  // 所有范围
                    // authorizedGrantTypes("authorization_code");     // 授权类型:授权码模式
                    authorizedGrantTypes("password");     // 授权类型:密码模式
        }
    }

    授权管理器Bean的注入:

    package cn.zeal4j.configuration;
    
    import org.omg.CORBA.PUBLIC_MEMBER;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    /**
     * @author Administrator
     * @file Spring-Security + Oauth2
     * @create 2020 09 29 11:35
     */
    @Configuration
    @EnableWebSecurity
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
        @Bean
        public PasswordEncoder getPasswordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        @Override
        @Bean
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }
    
        @Override
        protected void configure(HttpSecurity httpSecurity) throws Exception {
            httpSecurity.
                    csrf().
                        disable().
                    authorizeRequests().
                        antMatchers("/login/**","/logout/**","/oauth/**/").permitAll().
                        anyRequest().authenticated().
                        and().
                        formLogin().permitAll();
    
    
    //        // csrf
    //        httpSecurity.csrf().disable();
    //
    //        // 登录,退出,授权放行
    //        httpSecurity.authorizeRequests().antMatchers("/login/**","/logout/**","/oauth/**/").permitAll();
    //
    //        // 允许表单登录
    //        httpSecurity.formLogin().permitAll();
    //
    //        // 其余请求权限拦截
    //        httpSecurity.authorizeRequests().anyRequest().authenticated();
        }
    }

    Postman请求的地址和前面的密码不变,但是更改授权参数

    {
        "access_token": "8e51bdc3-50cd-42bd-b41c-28f06e5eca1f",
        "token_type": "bearer",
        "expires_in": 43199,
        "scope": "all"
    }

    用密码模式的令牌获取用户主体,也能拿到用户主体的信息:

  • 相关阅读:
    命令执行顺序控制与管道
    js获取返回首页
    手机站点击商务通无轨迹解决方法
    js文字向上滚动代码
    文字隐藏多余的文字
    QQ弹窗代码
    百度推送代码
    js手机站跳转
    js 判断时间,满足执行框架
    js切换换class
  • 原文地址:https://www.cnblogs.com/mindzone/p/13748996.html
Copyright © 2020-2023  润新知