单点登录原理
单点登录(Single Sign-On,简称SSO)是一种身份验证机制,允许用户只需一次登录,便能够访问多个相关系统或应用,而无需重复输入用户名和密码。下面将详细解释单点登录的原理:
- 用户访问主应用:用户在客户端通过浏览器或移动应用程序访问主应用,并尝试进行登录操作。
- 主应用认证:主应用接收到用户的登录请求后,验证用户提供的用户名和密码是否正确。如果认证成功,则生成一个用于标识用户身份的特定凭证或令牌。
凭证颁发:主应用将生成的凭证或令牌发送给用户浏览器,通常以Cookie或Token的形式进行存储。
子应用访问:当用户尝试访问其他子应用时,子应用会检测用户是否已登录。如果用户未登录,则重定向至主应用的登录页面。
单点登录验证:在重定向至主应用的登录页面后,子应用将用户重定向URL添加一个参数,包含子应用的标识信息。用户浏览器携带凭证或令牌访问主应用。
凭证验证:主应用接收到带有凭证或令牌的请求后,会解析验证凭证的有效性和合法性。主应用可能会使用加密算法验证凭证的完整性和真实性,确保凭证有效。
用户身份确认:一旦主应用确认凭证有效,则将用户视为已登录,并生成一个会话或认证令牌。该令牌将作为响应返回给用户浏览器。
子应用授权:用户浏览器将获取到的会话或认证令牌发送给子应用。子应用接收到令牌后,可以向主应用验证其有效性。主应用确认令牌有效后,子应用即可通过该令牌完成用户身份确认,并授权用户访问其资源。
统一认证原理
统一认证(Unified Authentication)是一种集中管理多个子系统的用户身份验证和授权过程的机制,以实现用户在不同系统中的一致登录和权限管理。下面将详细解释统一认证的原理:
- 用户访问应用系统:用户在客户端通过浏览器或移动应用程序访问某个应用系统,并尝试进行登录操作。
- 应用系统认证:应用系统接收到用户的登录请求后,验证用户提供的用户名和密码是否正确。如果认证成功,则生成一个用于标识用户身份的特定凭证或令牌。
- 统一认证中心:在统一认证环境中,存在一个专门负责用户身份验证和授权的统一认证中心。应用系统将用户的认证请求转发至统一认证中心进行处理。
- 用户身份认证:统一认证中心接收到应用系统的认证请求后,对用户提供的用户名和密码进行认证。认证中心可能会通过与用户存储的身份信息进行比对来验证用户身份的真实性。
- 状态维护:一旦用户身份认证成功,统一认证中心会为用户生成一个会话或认证令牌,并记录用户的登录状态。可以使用Cookie、Token或其他方式将会话或认证令牌发送给用户浏览器。
- 令牌传递:经过认证后,统一认证中心将用户的会话或认证令牌返回给应用系统。这个令牌是应用系统与统一认证中心之间进行交互的凭证,也是应用系统验证用户身份的依据。
- 子系统授权:应用系统接收到统一认证中心返回的会话或认证令牌后,可以向统一认证中心验证令牌的有效性和合法性。一旦验证通过,应用系统即可确认用户身份,并为用户授予相应的权限
两者的区别
单点登录 (SSO) | 统一认证 (Unified Authentication) | |
---|---|---|
定义 | 用户只需登录一次,即可访问多个应用系统。 | 用户通过一个中心化的认证系统进行身份验证和授权。 |
流程 | 用户登录后,通过认证中心颁发的令牌实现免密登录其他应用系统。 | 用户直接与统一认证中心进行交互,由认证中心验证身份并授权。 |
身份验证 | 认证中心负责验证用户身份,并生成令牌用于后续访问应用系统。 | 统一认证中心负责验证用户身份,并生成令牌用于后续访问应用系统。 |
应用系统集成 | 应用系统之间需要与认证中心建立信任关系,以验证令牌的有效性。 | 应用系统之间需要与统一认证中心建立信任关系,以验证令牌的有效性。 |
可扩展性 | 可支持多种不同的认证方式和协议。 | 可支持多种不同的认证方式和协议。 |
用户体验 | 用户只需进行一次登录,无需重复输入用户名和密码。 | 用户只需进行一次登录,无需重复输入用户名和密码。 |
隐私保护 | 用户个人信息在不同应用系统间共享较少,隐私更易得到保护。 | 用户个人信息在统一认证中心集中管理,需要注意隐私保护。 |
要实现单点登录,通常会使用统一认证作为基础,将用户的登录状态在不同系统间进行共享。因此,在某些情况下,可以将统一认证看作是实现单点登录的一种方式、
前端如何实现
以下代码均为简单示例,实际情况将更为复杂
要在前端实现单点登录 (SSO),需要利用后端提供的认证中心或身份提供者来处理用户的认证和生成令牌。
实现单点登录
首先我们需要使用axios
来进行后端请求。
import React, {
useEffect } from 'react';
import axios from 'axios';
const SSO = () => {
useEffect(() => {
// 发送登录请求到认证中心
axios.post('http://认证中心地址/sso/login', {
username: '用户名',
password: '密码'
})
.then(response => {
// 登录成功,得到认证中心返回的令牌
const token = response.data.token;
// 将令牌保存在本地存储或 cookie 中
localStorage.setItem('token', token);
// 跳转到其他应用系统
window.location.href = 'http://其他应用系统地址';
})
.catch(error => {
// 登录失败,处理错误逻辑
console.error('登录失败:', error);
});
}, []);
return (
<div>
正在进行单点登录...
</div>
);
};
export default SSO;
通过 useEffect
钩子函数,在组件加载时发送登录请求到认证中心。认证中心验证用户名和密码,并返回令牌。然后,将令牌保存在本地存储或 cookie 中(根据实际需求),最后跳转到其他应用系统。
实现统一认证
在前端代码中,如果我们想要实现统一认证
登录,那么就可能要安装第三方库 oidc-client
,它是一个用于客户端实现 OpenID Connect 的 JavaScript 库
npm install oidc-client
然后,在前端代码中引入 oidc-client
,并编写统一认证登录的逻辑:
import React, {
useEffect } from 'react';
import {
UserManager } from 'oidc-client';
const Login = () => {
useEffect(() => {
const userManager = new UserManager({
authority: '认证中心地址',
client_id: '客户端ID',
redirect_uri: '重定向URI',
response_type: 'code',
scope: 'openid profile',
silent_redirect_uri: '静默刷新URI',
automaticSilentRenew: true,
filterProtocolClaims: true
});
// 检查是否已经登录,如果已经登录则自动跳转到其他页面
userManager.getUser().then(user => {
if (user) {
window.location.href = '其他页面地址';
}
});
// 处理认证回调
userManager.signinRedirectCallback().then(user => {
// 登录成功,跳转到其他页面
window.location.href = '其他页面地址';
}).catch(error => {
// 登录失败,处理错误逻辑
console.error('登录失败:', error);
});
}, []);
const handleLogin = () => {
// 触发认证中心登录流程
userManager.signinRedirect();
};
return (
<div>
<button onClick={
handleLogin}>统一认证登录</button>
</div>
);
};
export default Login;
通过 oidc-client
创建一个 UserManager
实例,并根据实际情况配置认证中心的地址、客户端ID、重定向URI等参数。然后,使用 getUser()
方法检查用户是否已经登录,如果已经登录,则自动跳转到其他页面。
当点击 "统一认证登录" 按钮时,调用 signinRedirect()
方法触发认证中心的登录流程,并将用户重定向到认证中心进行身份验证。在认证回调页面中,调用 signinRedirectCallback()
方法处理认证结果,并获取用户信息。如果登录成功,可以将用户重定向到其他页面。
后端如何实现
经过对朋友的“拷打”终于让我逼问出Java是如何实现这两者的功能。
在Java中实现统一认证登录时,可以使用不同的框架和库,如Spring Security
、OAuth 2.0
、OpenID
等
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
@SpringBootApplication
@EnableWebSecurity // 启用Web安全功能
@EnableOAuth2Client // 启用OAuth 2.0客户端功能
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
import org.springframework.beans.factory.annotation.Autowired;
// import ...
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true) // 启用全局方法级安全注解,如@PreAuthorize和@PostAuthorize
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private OAuth2AuthorizedClientService clientService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login**", "/error**")
.permitAll() // 允许/login和/error路径的任意请求
.anyRequest()
.authenticated() // 其他路径需要认证后才能访问
.and()
.oauth2Login() // 配置OAuth 2.0登录支持
.loginPage("/login") // 指定自定义的登录页面路径
.defaultSuccessUrl("/success") // 登录成功后的默认跳转路径
.failureUrl("/error") // 登录失败后的跳转路径
.and()
.logout() // 配置退出登录的处理
.logoutRequestMatcher(new AntPathRequestMatcher("/logout")) // 指定退出登录的URL匹配规则
.logoutSuccessUrl("/login") // 退出登录后的跳转路径
.deleteCookies("JSESSIONID"); // 退出登录时删除指定的cookie
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// 根据需要添加用户认证逻辑,例如从数据库中验证用户信息、集成第三方身份提供者等
}
}
在上面代码里定义了一个名为SecurityConfig
的配置类,继承自WebSecurityConfigurerAdapter
,用于配置Spring Security的安全策略。
通过@EnableGlobalMethodSecurity(prePostEnabled = true)
注解,启用了全局方法级安全注解,如@PreAuthorize
和@PostAuthorize
,以便在代码中使用注解控制方法的访问权限。
在configure(HttpSecurity http)
方法中,配置了URL的访问权限。其中,.antMatchers("/login**", "/error**").permitAll()
表示允许/login
和/error
路径的任意请求,.anyRequest().authenticated()
表示其他路径需要经过认证才能访问。然后配置了OAuth 2.0的登录支持,设置了登录页面路径、默认成功跳转路径和失败跳转路径。最后,我们配置了退出登录的处理,包括退出URL匹配规则、退出成功后的跳转路径和要删除的cookie。
在configureGlobal(AuthenticationManagerBuilder auth)
方法中,可以根据需要添加用户认证逻辑,例如从数据库中验证用户信息、集成第三方身份提供者等,以实现具体的认证功能。
总结
总结起来,与前端代码相比,Java后端代码中的主要区别在于使用了Spring Security库来处理认证和授权的逻辑,通过配置类来定义URL的访问权限、认证方式等。