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

微服务架构09-单点登录系统01

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

微服务架构09-单点登录系统01

简介 背景分析

传统的登录系统中,每个站点都实现了自己的专用登录模块。各站点的登录状态相互不认可,各站点需要逐一手工登录。例如:

 这样的系统,我们又称之为多点登陆系统。应用起来相对繁琐(每次访问资源服务都需要重新登陆认证和授权)。与此同时,系统代码的重复也比较高。由此单点登陆系统诞生。

单点登陆系统

单点登录,英文是 Single Sign On(缩写为 SSO)。即多个站点共用一台认证授权服务器,用户在其中任何一个站点登录后,可以免登录访问其他所有站点。而且,各站点间可以通过该登录状态直接交互。例如:

快速入门实践 工程结构如下

基于资源服务工程添加单点登陆认证和授权服务,工程结构定义如下:

创建认证授权工程

添加项目依赖
  
        org.springframework.boot
        spring-boot-starter-web
    
    
        org.springframework.cloud
        spring-cloud-starter-oauth2
    
    
        com.alibaba.cloud
        spring-cloud-starter-alibaba-nacos-discovery
    
    
        com.alibaba.cloud
        spring-cloud-starter-alibaba-nacos-config
    

构建项目配置文件

在sca-auth工程中创建bootstrap.yml文件,例如:

server:
  port: 8071
spring:
  application:
    name: sca-auth
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
      config:
        server-addr: localhost:8848
添加项目启动类
package com.jt;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ResourceAuthApplication {
    public static void main(String[] args) {
        SpringApplication.run(ResourceAuthApplication.class, args);
    }
}
启动并访问项目

项目启动时,系统会默认生成一个登陆密码,例如:

 

打开浏览器输入http://localhost:8071呈现登陆页面,例如:

 其中,默认用户名为user,密码为系统启动时,在控制台呈现的密码。执行登陆测试,登陆成功进入如下界面(因为没有定义登陆页面,所以会出现404):

自定义登陆逻辑 业务描述

我们的单点登录系统最终会按照如下结构进行设计和实现,例如:

 我们在实现登录时,会在UI工程中,定义登录页面(login.html),然后在页面中输入自己的登陆账号,登陆密码,将请求提交给网关,然后网关将请求转发到auth工程,登陆成功和失败要返回json数据,在这个章节我们会按这个业务逐步进行实现

定义安全配置类

修改SecurityConfig配置类,添加登录成功或失败的处理逻辑,例如:

package com.cy.config;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //初始化加密对象
    //此对象提供了一种不可逆的加密方式,相对于md5方式更加安全
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //super.configure(http);
        //1.关闭(禁用)跨域攻击
        http.csrf().disable();
        //2.放行所有资源的访问(也可以放行登录操作请求,其他基于需求自定义)
        http.authorizeRequests().anyRequest().permitAll();
        //放行指定资源,其他资源需要验证
//        //http.authorizeRequests().antMatchers("index.html")
//                                .permitAll()
//                                .anyRequest()
//                                .authenticated();
//

        

        //3.定义登录成功和失败以后的处理逻辑
        //假如没有如下设置登录成功会显示404
        //http.formLogin这句话会对外暴露一个登录路径/login
        http.formLogin().successHandler(successHandler())
                        .failureHandler(failureHandler());

    }

    //定义认证成功以后的处理器
    @Bean
    public AuthenticationSuccessHandler successHandler() {
        return (request,response,authentication) ->{
            //构建map对象封装到要响应到客户端数据
            Map map = new HashMap<>();
            map.put("state",200);
            map.put("message","login ok");
            //将map对象转换为json格式字符串写到客户端
            writeJsonToClient(response,map);
        };
    }



    //定义认证失败以后的处理器
    @Bean
    public AuthenticationFailureHandler failureHandler() {
        return (request,response,exception) ->{
            //构建map对象封装到要响应到客户端数据
            Map map = new HashMap<>();
            map.put("state",500);
            map.put("message","login error");
            //将map对象转换为json格式字符串写到客户端
            writeJsonToClient(response,map);
        };
    }

    private void writeJsonToClient(HttpServletResponse response,Map< String,Object> map)throws IOException {
        String json = new ObjectMapper()
                    .writevalueAsString(map);
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json:charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println(json);
        out.flush();
    }
}

定义用户信息处理对象

在spring security应用中底层会借助UserDetailService对象获取数据库信息,并进行封装,最后返回给认证管理器,完成认证操作,例如

package com.cy.service;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
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.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        //1.基于用户名查询用户信息(暂时先给假数据)
        String encodePassword = //假设这个密码来自数据库
                passwordEncoder.encode("123456");

        //2.封装查询到信息并返回
        //
        //AuthorityUtils.createAuthorityList("sys:res:create","sys:res:retrieve");
        return new User(username,
                encodePassword,//必须是已加密的密码
                AuthorityUtils.createAuthorityList("sys:res:create","sys:res:retrieve"));
    }
}
网关中登陆路由配置

在网关配置文件中添加登录路由配置,例如

 - id: router02
   uri: lb://sca-auth  #lb表示负载均衡,底层默认使用ribbon实现
   predicates: #定义请求规则(请求需要按照此规则设计)
      - Path=/auth/login/** #请求路径设计
   filters:
      - StripPrefix=1 #转发之前去掉path中第一层路径
基于Postman进行访问测试

启动sca-gateway,sca-auth服务,然后基于postman访问网关,执行登录测试,例如:

 

自定义登陆页面

在sca-resource-ui工程的static目录中定义登陆页面,例如:




    
    
    
    
    
    login



    Please Login
    

启动sca-resource-ui服务后,进入登陆页面,输入用户名jack,密码123456进行登陆测试。

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

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

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