SSO单点登陆实现思路和改造方法

单点登陆(SSO

修改记录

文件编号

版本号

拟制人/修改人

拟制/修改日期

更改理由

主要更改内容

(写要点即可)

注1:每次更改归档文件,需填写此表

注2:文件第一次归档时,“主要更改内容”栏写无。

目录

1.单点登录接口文档

    1.1.基础概念

1.2中心门户

  1.2.1中心门户SSO流程图

      1.2.2中心门户SSO 接口

1.3子系统接口

1.3.1子系统接口介绍

1.3.2 Token登录接口

1.3.3 Username+Token登录接口

2.单点登录实现的改造

2.1改造原理

2.2 SpringSecurity实现单点登录原理

2.3 Shiro 实现单点登录原理

  1. 单点登录接口文档

1.1基础概念:SSO

SSO英文全称Single Sign On,单点登录。SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。它包括可以将这次主要的登录映射到其他应用中用于同一个用户的登录的机制。它是目前比较流行的企业业务整合的解决方案之一。

本文中的  中心门户  指的是一个系统,在一个企业下有许多系统,企业用户在登录这个系统以后,不需要输入账号密码,就可以跳转到他想要去的 子系统 并且完成登录 ,本文档就用于实现,改造,完成该功能

1.2中心门户接口

1.2.1 中心门户SSO流程图

SSO单点登陆实现思路和改造方法_第1张图片

 

1.2.2中心门户SSO 接口

用户在登录 中心门户 后,点击网页上显示的子系统,触发前端的点击事件,将调用后端的登录接口

接口信息

http://.../api/sso/ssoToken

接口方式

public AjaxResult test(HttpServletRequest request,

HttpServletResponse response)

接口类型

Restful

接口编码

UTF-8

调用方式

POST

调用端

中心门户前端页面

(本借口由于接收的参数较多,使用Resquest来做形参接受参数,在方法体内进行取值,调用相应的接口完成功能的实现)

具体接收的参数有:

参数名

参数类型

参数备注

username

String

当前登录用户的用户名

token

String

当前登录用户的TOKEN

webid

String

要实现SSO的子系统的url

在中心门户实现SSO后,系统会记录本次SSO的结构,存放在数据库中,表名为tab_single_point_log

字段名

类型

注释

single_point_id

Int 

主键

user_id

Int

单点登录用户id

web_id

Int

目标系统id

token

varchar

实现SSO的TOKEN

single_point_statu

Int

0正常 1失败

single_point_time

Datetime

完成SSO时间

single_point_describe

varchar

SSO事件描述

1.3 子系统接口

1.3.1子系统接口介绍

子系统完成SSO登录共有两个接口,两个接口的功能都是实现了自定义登录,详情见1.2.1的流程图,其大致思路为:先采用Token登录,当Token完成不了系统的验证就采用Username+Token登录

1.3.2 Token登录接口

接口信息

http://.../user/loginByToken

接口方式

public ResponseResult loginByToken

(@RequestBody UserSso userSso)

接口类型

Restful

接口编码

UTF-8

调用方式

POST

调用端

中心门户

返回值ResponseResult:

参数

类型 

备注

Code

Integer

返回代码 200成功 其他失败

Msg

String

返回信息

Data

泛型

携带的返回参数

1.3.3 Username+Token登录接口

接口信息

http://.../user/loginByUserNameAndToken

接口方式

public ResponseResult loginByUserNameAndToken

(@RequestBody UserSso userSso)

接口类型

Restful

接口编码

UTF-8

调用方式

POST

调用端

中心门户

返回值ResponseResult:

参数

类型 

备注

Code

Integer

返回代码 200成功 其他失败

Msg

String

返回信息

Data

泛型

携带的返回参数

  1. 单点登录实现的改造
    1. 改造原理

本文档实现SSO的原理,其实是通过浏览器Cookies实现,考虑到Cookie存在浏览器中,可以被不同的系统读取,实现跨域,完成登录的验证。同时需要改造系统自定义认证和授权,目前主流的框架有SpringSecurity和Shiro,本文档就两种热门框架,以前后端分离的主流系统,完成了SSO demo的认证。

由于各系统的授权系统不一致,本文就没有过多描述,实现方法原理也很简单,在用户完成授权时将用户权限加入到认证体中,即可完成。

    1. SpringSecurity实现单点登录原理

首先SpringSecurity工作过程原理:

SSO单点登陆实现思路和改造方法_第2张图片

 

几个重要的组件

Authentication:(接口):用户输入账号密码可以是Authentication 手机号+验证码也可以是Authentication 所以Authenticaion是一次登陆请求操作的载体。可以看一个Authenticaion的一个实现类例子

SSO单点登陆实现思路和改造方法_第3张图片

 

principal:用户名用于可唯一标识用户信息的属性

Credentials:存储密码作为用户端鉴权凭证

构造方法对比:

构造方法对比:

public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {

    super((Collection)null);

    this.principal = principal;

    this.credentials = credentials;

    this.setAuthenticated(false);

}

public UsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection authorities) {

    super(authorities);

    this.principal = principal;

    this.credentials = credentials;

    super.setAuthenticated(true);

}

第一个构造方法是用来构造一个未被认证过的实体类

第二个构造方式是返回一个已经被认证过的实体类 表示已经认证成功

Provider:Provider是AuthenticaionManger下中List

SSO单点登陆实现思路和改造方法_第4张图片

 

他是对具体的Authentication的认证管理,来认证这个Authentication的

认证成功,就返回带认证的Authencation 认证失败 抛出异常

方法:

public interface AuthenticationProvider {

//验证

     Authentication authenticate(Authentication authentication) throws AuthenticationException;

//表面支持哪种Authenticaion

     boolean supports(Class authentication);

}

Filter过滤

例子:

SSO单点登陆实现思路和改造方法_第5张图片

FilterChain

方法filterChain.doFilter(request,response);

SecurityConfig:

配置类 配置具体的配置


@Bean

@Override

public AuthenticationManager authenticationManagerBean() throws Exception {

    return super.authenticationManagerBean();

}

@Override

protected void configure(HttpSecurity http) throws Exception {



    http

            .csrf().disable()

            //不通过Session获取SecurityContext

            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)

            .and()

            .authorizeRequests()

            // 对于登录接口 允许匿名访问

            .antMatchers("/user/login").anonymous()

            .antMatchers("/user/getcode").anonymous()

            .antMatchers("/user/loginByCode").anonymous()



            // 除上面外的所有请求全部需要鉴权认证

            .anyRequest().authenticated()

            .and()

            .addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);



    ;

}

注入provider和绑定



@Override

protected void configure(AuthenticationManagerBuilder auth) throws Exception {

    auth.userDetailsService(this.userDetailsService)

            .passwordEncoder(this.passwordEncoder())

            .and()

            .authenticationProvider(userCodeAuthenticationProvider())

            .authenticationProvider(authenticationProvider());

}

总结SpringSecurity验证流程:

1.请求接口 接受参数

SSO单点登陆实现思路和改造方法_第6张图片

 

2.包装请求参数 交给authenticationManager中验证

SSO单点登陆实现思路和改造方法_第7张图片

 

3.包装好的Authentication传入authenticationManager,在List找到可以处理的对应的Provider,传入Provider中

SSO单点登陆实现思路和改造方法_第8张图片

 

正确的话就返回以及认证过的Authenticaion,发送到Service层 最后返回登陆成功的消息

FilterChina在这一切之前

 

因此SpringSecurity完成SSO就是要自定义token登录和username+token登录,具体方法可以看demo中的

    1. Shiro 实现单点登录原理

SSO单点登陆实现思路和改造方法_第9张图片

 

Shiro和SpringSecurity实现过程大差不差,重要的几个方法:

Subject = SecurityUtils.getSubject();
subject.login(new UsernamePasswordToken(user.getUsername(),user.getPassword()));


/**
    public class UsernameAndToken implements AuthenticationToken {

    private String token;
    private String username;
**/

public class UsernameAndTokenRealm extends AuthorizingRealm {
@Override
public boolean supports(AuthenticationToken token) {
    return token instanceof UsernameAndToken;
}

@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    UsernameAndToken shiroAuthToken = (UsernameAndToken) authenticationToken;
    if(认证成功)
     return new SimpleAuthenticationInfo(username,token, "UsernameAndToken");
    }
    else{
        System.out.println("invalid username");
        throw new  AuthenticationException("认证失败");

    }
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
   授权
}
}

自定义Realm以及Token便可以完成认证

你可能感兴趣的:(java,开发语言,spring)