栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

单点登录学习

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

单点登录学习

概述

单点登录,英文是 Single Sign On(缩写为 SSO)。就是多个站点公用一台认证服务器,比如下图我刚回答了个问题,在写一篇博客,是不需要再次登录的;而且各站点可以通过该登录状态实现交互。

**注意:登录是一个独立的系统如下图:**不管在系统1还是系统2登录,他们都会去调用认证授权,其目的就是为了保护数据安全性,判断用户的合法性!

快速入门
    单点登陆系统解决方案设计
    本次项目中用到的技术有①JWT ②SpringSecurity安全框架 ③OAuth2

JWT解释
注:JWT中不会存储用户密码,一般存储权限等

    创建父工程sso 修改pom和配置文件并且在父工程中定义版本
1.父工程maven


    4.0.0

    com.jt
    02-sso
    pom
    1.0-SNAPSHOT
    
        sso-system
    

    
    
        
            
            
                org.springframework.boot
                spring-boot-dependencies
                2.3.2.RELEASE
                pom
                import
            
            
            
                org.springframework.cloud
                spring-cloud-dependencies
                Hoxton.SR9
                pom
                import
            
            
            
                com.alibaba.cloud
                spring-cloud-alibaba-dependencies
                2.2.6.RELEASE
                pom
                import
            
        
    

    
        
            org.projectlombok
            lombok
            provided
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
            
            
                
                    org.junit.vintage
                    junit-vintage-engine
                
            
        
    

        
    
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                3.8.1
                
                    8
                    8
                
            
        
    



1.2在创建一个子工程sso-system继承父工程


    
        02-sso
        com.jt
        1.0-SNAPSHOT
    
    4.0.0

    sso-system
    
        
        
            mysql
            mysql-connector-java
        
        
        
            com.baomidou
            mybatis-plus-boot-starter
            3.4.2
        
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-config
        
        
        
            org.springframework.boot
            spring-boot-starter-web
        
    



编写配置文件bootstrap.yml

server:
  port: 8061
spring:
  application:
    name: sso-system
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        file-extension: yml
      discovery:
        server-addr: localhost:8848
  datasource:
    url: jdbc:mysql:///jt-sso?serverTimezone=Asia/Shanghai&characterEncoding=utf8
    username: root
    password: root
    
logging:
  level:
    com.jt: debug

然后测试一下数据控连接
创建实体类User

创建mapper实现基于用户名称查询用户信息和基于用户id查询用户权限

1.3统一认证工程auth

统一认证工程的设计及实现
目的:用户登录时,调用此工程对用户身份进行核验,并授权

pom依赖



    
        02-sso
        com.jt
        1.0-SNAPSHOT
    
    4.0.0

    sso-auth

    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        
        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        

        
        
            org.springframework.cloud
            spring-cloud-starter-oauth2
        
    



配置文件

server:
  port: 8071
spring:
  application:
    name: sso-auth
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
      config:
        server-addr: localhost:8848
        file-extension: yml

启动类

启动类启动成功后会在控制台生成一个秘钥,然后访问端口号进去一个SpringSecurity进入一个页面,user为底层创建的用户,秘钥控制台生成,登录以后404则代表登录成功,因为没有要跳转的页面,会出现404异常


定义用户信息处理对象
定义User:用于封装sso-system工程去查询到的用户信息
定义远程service对象,用于实现远程用户信息调用

定义用户登陆业务逻辑处理对象

package com.jt.auth.service.impl;

import com.jt.auth.service.RemoteUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.List;


@Service
public class UserDetailServiceImpl implements UserDetailsService {

    
    @Autowired
    private RemoteUserService remoteUserService;

    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //1.基于用户名获取远端(现在这里指system服务)用户信息
        com.jt.auth.pojo.User user = remoteUserService.listUserByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("用户不存在");
        }

        //2.基于远端用户id获取用户权限id
        List userPermissions =
                remoteUserService.listUserByUserIdPermissions(user.getId());

        //3.封装用户信息并返回,交给认证管理器(AuthenticationManager)对用户身份进行认证
        return new User(username,
                user.getPassword(),
                AuthorityUtils.createAuthorityList(
                        userPermissions.toArray(new String[]{})));
        //AuthenticationManager这个接口底层已经提供好认证方法,这里只用给他提供数据即可
    }
}

定义Security配置类

package com.jt.auth.config;

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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

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

定义Oauth2认证授权配置

package com.jt.auth.config;

import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
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;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;


@AllArgsConstructor
@Configuration
@EnableAuthorizationServer
public class Oauth2Config extends AuthorizationServerConfigurerAdapter {
    
    private BCryptPasswordEncoder passwordEncoder;
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()//把规则写到内存里
                .withClient("gateway-client")//定义客户端的标识(客户端到认证服务地址去认证时,需要携带这个信息)
                .secret(passwordEncoder.encode("123456"))//定义客户端携带的秘钥
                .authorizedGrantTypes("password", "refresh_token")//定义授权的类型,password基于密码进行认证,refresh_token基于刷新令牌认证
                .scopes("all");//满足以上条件的客户端都可以认证
    }
    
    
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.tokenKeyAccess("permitAll()")//公开,定义这个认证地址(/oauth/token)
                // 用户携带资料到这个地址认证,permitAll()允许所有的到这里认证
                .checkTokenAccess("permitAll()")//公开校验token的地址(/oauth/check_token)
                .allowFormAuthenticationForClients();//允许form表单的认证方式
    }
    
    
    private AuthenticationManager authenticationManager;
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager)//指定这个认证管理器对象完成认证
                .tokenServices(tokenServices());//定义令牌服务(有默认令牌服务,但默认令牌服务不满足我们的需求)
    }

    private TokenStore tokenStore;
    private JwtAccessTokenConverter jwtAccessTokenConverter;
    @Bean
    public AuthorizationServerTokenServices tokenServices() {
        //1.构建令牌服务对象
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        //2.设置令牌创建及存储
        tokenServices.setTokenStore(tokenStore);
        //3.设置令牌增强器(默认是uuid格式的令牌)
        tokenServices.setTokenEnhancer(jwtAccessTokenConverter);
        //4.设置刷新令牌(服务端要创建一个刷新令牌)
        tokenServices.setSupportRefreshToken(true);
        //5.设置访问令牌,设置令牌的有效期
        tokenServices.setAccessTokenValiditySeconds(3600);
        //6.设置刷新令牌
        tokenServices.setRefreshTokenValiditySeconds(5400);
        return tokenServices;
    }
}


但是认证完后需要颁发令牌,默认的不满足我们要求,需要我们手动配置,此类是给上边Oauth2认证授权配置服务的

1.4资源服务工程sso-resource

pom依赖



    
        02-sso
        com.jt
        1.0-SNAPSHOT
    
    4.0.0

    sso-resource

    
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        

        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-config
        

        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-sentinel
        

        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        

        
        
            org.springframework.cloud
            spring-cloud-starter-oauth2
        
    


配置类

server:
  port: 8881
spring:
  application:
    name: sso-resource
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        file-extension: yml
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8180

启动类

配置类


controller

package com.jt.resource.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/resource")
public class ResourceController {

    
    @PreAuthorize("hasAuthority('sys:res:list')")
    @GetMapping
    public String doSelect() {
        return "select resource ok";
    }

    @PreAuthorize("hasAuthority('sys:res:create')")
    @PostMapping
    public String doCreate() {
        return "create resource ok";
    }

    @PreAuthorize("hasAuthority('sys:res:update')")
    @PutMapping
    public String doUpdate() {
        return "update resource ok";
    }

    @PreAuthorize("hasAuthority('sys:res:delete')")
    @DeleteMapping
    public String doDelete() {
        return "delete resource ok";
    }

    
    @GetMapping("/export")
    public String doExport() {
        return "export resource ok";
    }
}

定义一个匿名就可以访问资源的controller

package com.jt.resource.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/resource")
public class ResourceController {

    
    @PreAuthorize("hasAuthority('sys:res:list')")
    @GetMapping
    public String doSelect() {
        return "select resource ok";
    }

    @PreAuthorize("hasAuthority('sys:res:create')")
    @PostMapping
    public String doCreate() {
        return "create resource ok";
    }

    @PreAuthorize("hasAuthority('sys:res:update')")
    @PutMapping
    public String doUpdate() {
        return "update resource ok";
    }

    @PreAuthorize("hasAuthority('sys:res:delete')")
    @DeleteMapping
    public String doDelete() {
        return "delete resource ok";
    }

    
    @GetMapping("/export")
    public String doExport() {
        return "export resource ok";
    }
}

测试

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/724084.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号