SpringSecurity+OAuth2.0+JWT实现单点登录应用

news2024/11/19 7:25:53

SpringSecurity+OAuth2.0+JWT实现单点登录应用
gitee项目练习地址:https://gitee.com/xzq25_com/springsecurity.oauth2

OAuth2.0单点登录实践

  • 一、搭建OAuth授权服务器,采用授权码模式+JWT令牌
  • 二、创建服务client:SSOA、SSOB 并进行测试

一、搭建OAuth授权服务器,采用授权码模式+JWT令牌

目录如下:
在这里插入图片描述

1,导入依赖:

   <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-security</artifactId>
        </dependency>
        
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

2,配置AuthorizationServerConfig认证授权服务

/**
 * @author xzq
 * @description: 授权服务器
 * @date 2022/12/5 13:43
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private TokenStore jwtTokenStore;

    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;

    @Autowired
    private JwtTokenEnhancer jwtTokenEnhancer;

    /**
     * @description: 使用密码模式所需配置
     * @author liyonghui
     * @date 2021/12/5 14:27
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

        List<TokenEnhancer> delegates = new ArrayList<>();
        delegates.add(jwtTokenEnhancer);
        delegates.add(jwtAccessTokenConverter);

        //配置JWT内容增强
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(delegates);

        //配置存储令牌策略
        endpoints.tokenStore(jwtTokenStore)
                .accessTokenConverter(jwtAccessTokenConverter)
                .tokenEnhancer(tokenEnhancerChain);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                //配置client-id
                .withClient("super")
                //配置client-secret
                .secret(passwordEncoder.encode("xxx"))
                //配置刷新令牌的有效期
                .refreshTokenValiditySeconds(6000)
                //配置redirect-url,用于授权成功后跳转
                .redirectUris("http://localhost:8081/login","http://localhost:8082/login")
                //自动授权
                .autoApprove(true)
                //配置申请的权限范围
                .scopes("user","order","payment")
                //授权类型-使用授权码模式
                .authorizedGrantTypes("authorization_code","refresh_token");
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        //获取密钥需要身份认证,使用单点登录时必须配置
        security.tokenKeyAccess("isAuthenticated()");
    }
}

3,配置WebSecurityConfigurerAdapter

/**
 * @author xzq
 * @description: TODO
 * @date 2022/12/5 13:35
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

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

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

4,配置JwtTokenStoreConfig

/**
 * @author xzq
 * @description: TODO
 * @date 2022/12/5 15:39
 */
@Configuration
public class JwtTokenStoreConfig {

    @Bean
    public TokenStore jwtTokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        //配置JWT使用的秘钥
        jwtAccessTokenConverter.setSigningKey("test_key");
        return jwtAccessTokenConverter;
    }
}

5,配置JwtTokenEnhancer:Jwt增强

/**
 * @author liyonghui
 * @description: JWT内容增强
 * @date 2021/12/5 15:58
 */
@Component
public class JwtTokenEnhancer implements TokenEnhancer {

    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) {
        Map<String, Object> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("enhance", "enhance info");
        objectObjectHashMap.put("ceshi", "测试一下增强令牌!");
        ((DefaultOAuth2AccessToken) oAuth2AccessToken).setAdditionalInformation(objectObjectHashMap);
        return oAuth2AccessToken;
    }
}

6,配置pojo类

/**
 * @author xzq
 * @description: TODO
 * @date 2022/12/5 13:37
 */
public class User implements UserDetails {
    private String username;
    private String password;
    private List<GrantedAuthority> authorities;

    public User(String username, String password, List<GrantedAuthority> authorities) {
        this.username = username;
        this.password = password;
        this.authorities = 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;
    }
}

配置一个用户的账号密码

/**
 * @author xzq
 * @description: TODO
 * @date 2022/12/5 13:34
 */
@Service
public class UserService implements UserDetailsService {
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        String password = passwordEncoder.encode("123456");
        return new User("admin", password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
    }
}

二、创建服务client:SSOA、SSOB 并进行测试

创建client:SSOA
目录如下:
在这里插入图片描述
1,配置yml文件

server:
  port: 8081
  servlet:
    session:
      cookie:
        name: OAUTH2-CLIENT-SESSION01  # 防止cookie冲突

security:
  oauth2:
    client:
      client-id: super # appid
      client-secret: xxx #appsecret
      user-authorization-uri: http://localhost:8080/oauth/authorize #oauth认证地址
      access-token-uri: http://localhost:8080/oauth/token # 获取access_token

    resource:
     jwt:
        key-uri:  http://localhost:8080/oauth/token_key  # 获取和校验JWT(包装获取access_token)

写一个controller

/**
 * @Author xiaozq
 * @Date 2022/12/12 9:26
 * <p>@Description:</p>
 */
@RequestMapping
@RestController
public class SystemAController {

    @GetMapping("/user")
    public Object userinfo(Authentication authentication){
        return authentication;
    }

    @GetMapping("/info")
    public Object ssoinfo(Authentication authentication){
        return  "系统A单点登录";
    }
}

创建client:SSOB: 复制A系统,改一下yml文件的端口号和cookie名设置,如下:

server:
  port: 8082
  servlet:
    session:
      cookie:
        name: OAUTH2-CLIENT-SESSION02  # 防止cookie冲突

security:
  oauth2:
    client:
      client-id: super # appid
      client-secret: xxx #appsecret
      user-authorization-uri: http://localhost:8080/oauth/authorize #oauth认证地址
      access-token-uri: http://localhost:8080/oauth/token # 获取access_token

    resource:
     jwt:
        key-uri:  http://localhost:8080/oauth/token_key  # 获取和校验JWT(包装获取access_token)
        

开测!!!!
1,启动授权服务器,启动服务器A、B注意授权服务器先启动!!!

2,访问服务器A接口: http://localhost:8081/user

在这里插入图片描述
自动跳转到授权服务器的登录页面
输入用户名,密码: admin 123456
在这里插入图片描述
点击登录,则重定向回服务A,成功访问接口
在这里插入图片描述

上述截图响应的内容josn格式化如下:

{
    "authorities": [{
            "authority": "admin"
        }
    ],
    "details": {
        "remoteAddress": "0:0:0:0:0:0:0:1",
        "sessionId": "9143741264A37F6E57C921C0ACCAC86E",
        "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjZXNoaSI6Iua1i-ivleS4gOS4i-WinuW8uuS7pOeJjCEiLCJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInVzZXIiLCJvcmRlciIsInBheW1lbnQiXSwiZXhwIjoxNjcwODU1MDM2LCJhdXRob3JpdGllcyI6WyJhZG1pbiJdLCJqdGkiOiI1NDc3ZDMzNS01MzMwLTQ4NTQtYWFiMC0xYmU4OTMzZTQxNmEiLCJjbGllbnRfaWQiOiJzdXBlciIsImVuaGFuY2UiOiJlbmhhbmNlIGluZm8ifQ.N2MXqtGFjMkCo5ZaU5TCZdLr1IqfWB3kDmEUO-JH4cA",
        "tokenType": "bearer",
        "decodedDetails": null
    },
    "authenticated": true,
    "userAuthentication": {
        "authorities": [{
                "authority": "admin"
            }
        ],
        "details": null,
        "authenticated": true,
        "principal": "admin",
        "credentials": "N/A",
        "name": "admin"
    },
    "clientOnly": false,
    "oauth2Request": {
        "clientId": "super",
        "scope": ["user", "order", "payment"],
        "requestParameters": {
            "client_id": "super"
        },
        "resourceIds": [],
        "authorities": [],
        "approved": true,
        "refresh": false,
        "redirectUri": null,
        "responseTypes": [],
        "extensions": {},
        "grantType": null,
        "refreshTokenRequest": null
    },
    "credentials": "",
    "principal": "admin",
    "name": "admin"
}

此时在打开一个窗口,访问服务B
在这里插入图片描述
自动省略了上面sign in 登录步骤 ,自动重定向到服务B ,成功访问接口
在这里插入图片描述

至此,单点登录应用完成!!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/82243.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【云计算与大数据技术】大数据系统总体架构概述(Hadoop+MapReduce )

一、总体架构设计原则 企业级大数据应用框架需要满足业务的需求&#xff0c;一是要求能够满足基于数据容量大&#xff0c;数据类型多&#xff0c;数据流通快的大数据基本处理需求&#xff0c;能够支持大数据的采集&#xff0c;存储&#xff0c;处理和分析&#xff0c;二是要能…

openGauss数据库的使用

目录前言1. 启动/停止/重启数据库&#xff08;1&#xff09;极简版启动/停止/重启命令&#xff08;2&#xff09;企业版启动/停止/重启命令2. 登录数据库&#xff08;1&#xff09;登录数据库时的基本连接参数&#xff08;2&#xff09;登录数据库时的常用连接参数&#xff08;…

如何使用轻量应用服务器搭建高颜值的YesPlayMusic网易云播放器

本文介绍了如何使用腾讯云的Lighthouse轻量应用服务器来搭建一个高颜值的第三方网易云播放器。 ​ 项目简介 本文使用的是YesPlayMusic项目&#xff0c;这是一款高颜值的第三方网易云播放器&#xff0c;它完全可以作为网易云官方应用的替代品。而且还拥有一些网易云官方应用没…

react-dnd 拖拽能力教程

前言 近几年来&#xff0c;低代码、零代码的热度在国内逐年递增。“复杂度同力一样不会消失&#xff0c;也不会凭空产生&#xff0c;它总是从一个物体转移到另一个物体或一种形式转为另一种形式”。用户在使用低零代码构建应用程序时&#xff0c;这些能力只是被平台研发人员提…

SQL SERVER 2019卸载和安装

卸载过程删除SQL Server2019包括sql server这个数据库和它的管理工具SQLServer Management Studio以及他们的注册表信息和安装的目录&#xff0c;以上&#xff0c;最重要的是一定要有耐心&#xff0c;一步一步慢慢来。 首先打开一定要把SQL的服务都关掉&#xff0c;这个很重要…

压缩包文件如何设置加密、删除加密?

压缩包是将文件压缩成RAR、ZIP格式文件&#xff0c;将文件压缩成压缩包之后&#xff0c;就更方便转发以及保存&#xff0c;而且压缩包文件可以进行加密&#xff0c;这样也能够起到对文件的保护作用&#xff0c;今天和大家分享如何对压缩包进行加密以及如何删除压缩包密码。 压…

战略,就没一本好书

战略这个词被工商业界引爆&#xff0c;都是1965年的事。想来到现在已经快60年了。但是实话说&#xff0c;战略这么重要的事&#xff0c;其实没几本好书&#xff0c;也就是说&#xff0c;这个领域&#xff0c;实在没什么有效的研究成果。&#xff08;1&#xff09;起点1965年是个…

Vue 进阶二 | 系统性学习 | 无知的我费曼笔记

无知的我正在复盘Vue 该笔记特点是 重新整理了涉及资料的一些语言描述、排版而使用了自己的描述对一些地方做了补充说明。比如解释专有名词、类比说明、对比说明、注意事项提升了总结归纳性。尽可能在每个知识点上都使用一句话 || 关键词概括更注重在实际上怎么应用提出并回答…

数据可视化之卡塔尔世界杯,世界杯8强全部出炉,你看好那支队伍?

2022年下半年可算是集结了众多国际赛事&#xff0c;前有csgo major&#xff0c;英雄联盟总决赛&#xff0c;后有斯诺克英锦赛。当然这些赛事里面最万众瞩目的就是4年一度的卡塔尔世界杯了。本届世界杯开赛前最大的看点就是世界杯的花费&#xff0c;卡塔尔2022年世界杯花费2290亿…

他让我看重采样

周末邓总让我帮忙看下重采样的代码&#xff0c;然后我就用上了自己的神器。我的神器就是Google之后总结了下代码&#xff0c;完整的代码可以往下看&#xff0c;我们平时也会用到重采样&#xff0c;通道转换、交织和非交织的相互转换、给音频重新map等等。这些都是做音频需要搞的…

(红帽系统)redhat7.2 相关服务器配置

远程连接服务器配置 简介 使用SSH可以在本地主机和远程服务器之间进行加密的传输数据&#xff0c;实现数据的安全传输。而OpenSSH是SSH协议的免费开源实现&#xff0c;它采用安全加密的网络连接工具代替了telnet、ftp等 实现步骤 第一步 进入红帽系统 第二步 检查安装系统时…

需求处理的流程及问题挑战

本文主要讲需求的一般处理流程&#xff0c;以及可能存在的问题及挑战。 一、需求处理流程&#xff1a; 1、需求的生命周期&#xff1a; 起点是提需求&#xff0c;终点是拒绝或接受需求。每个人希望自己的需求能被接受或满足&#xff0c;但资源总是有限的。每个需求从产生到实…

SRM系统的国内品牌前五名是哪几家,大概价位是多少?

SRM系统的国内品牌前五名是哪几家&#xff0c;大概价位是多少&#xff1f;SRM系统是采购数字化转型过程中的产物&#xff0c;SRM系统与ERP与SCM系统打通后&#xff0c;能够破除信息壁垒&#xff0c;增加采购部门与业务部门的沟通效率&#xff0c;从而实现企业人、物、财成本的降…

JavaSE——多线程详细

目录 一、多线程 1.1 基本介绍 1.2 进程和线程的关系 1.3 多线程并发概念 二、实现线程的方式 2.1 继承Thread类 2.2 实现java.lang.Runnable接口 2.3 匿名类 2.4 实现Callable接口&#xff08;JDK8新特性&#xff09; 2.5 run和start的区别 2.6 线程声明周期 三、…

双非本科怎么了,照样拿到阿里 offer! 分享阿里技术四面 + 交叉面 +HR 面难忘经历

说一下 java 类加载器的工作机制&#xff1f;类加载在哪个区域进行的&#xff1f; 说一下 java 的线程模型&#xff1f; violate 了解吗&#xff1f;它的原理是什么&#xff1f;violate 是线程安全的吗&#xff1f; 保证线程安全的解决方法有哪些&#xff1f;说一说读写锁吧…

前端高频手写面试题总结

实现字符串的repeat方法 输入字符串s&#xff0c;以及其重复的次数&#xff0c;输出重复的结果&#xff0c;例如输入abc&#xff0c;2&#xff0c;输出abcabc。 function repeat(s, n) {return (new Array(n 1)).join(s); }递归&#xff1a; function repeat(s, n) {return…

通过 JFR 与日志深入探索 JVM - TLAB 原理详解

什么是 TLAB&#xff1f; TLAB&#xff08;Thread Local Allocation Buffer&#xff09;线程本地分配缓存区&#xff0c;这是一个线程专用的内存分配区域。既然是一个内存分配区域&#xff0c;我们就先要搞清楚 Java 内存大概是如何分配的。 我们一般认为 Java 中 new 的对象…

模板模式

文章目录思考模板模式1.模板模式的本质2.何时选用模板模式3.优缺点4.模板方法的结构5.实现思考模板模式 模板模式其实就是抽离共用方法到抽象类中&#xff0c;然后再规定其具体实现步骤 1.模板模式的本质 模板方法模式的本质:固定算法骨架。 模板方法模式主要是通过制定模板&am…

系统集成企业需具备哪些证书?

IT信息化企业&#xff0c;系统集成企业需要做的资质证书有哪些&#xff1f;经常遇到有新成立的系统集成商问智达鑫业小编&#xff0c;该申请哪些企业资质&#xff0c;接下来了小编整理下目前市场上使用频率比较高的一些资质证书&#xff0c;大家可以参考下。 信息系统建设和服务…

A-Level考试常见问题综合解答

关于A Level的Q&A 问&#xff1a;参加A Level的考试与其他考试相比有什么优势吗&#xff1f; 答&#xff1a;A Level考试的门数相较其他国际课程更少&#xff0c;学生有更多的时间花费在每门课上取得更好的GPA和最终成绩。问&#xff1a;就读的学校就直接提供A Level课程&a…