您好,登录后才能下订单哦!
在现代企业应用系统中,用户通常需要访问多个独立的系统或服务。传统的登录方式要求用户在每个系统中都进行身份验证,这不仅增加了用户的操作负担,还可能导致安全风险。单点登录(Single Sign-On, SSO)技术的出现,解决了这一问题。通过单点登录,用户只需进行一次身份验证,即可访问所有授权的系统和服务。
本文将详细介绍如何在SpringBoot中实现单点登录,涵盖单点登录的基本概念、实现原理、具体实现步骤、安全性考虑、性能优化以及扩展与集成等内容。
单点登录(Single Sign-On, SSO)是一种身份验证机制,允许用户通过一次登录访问多个相互信任的系统或服务。用户只需在一个系统中进行身份验证,即可获得访问其他系统的权限,而无需再次输入用户名和密码。
基于Cookie的单点登录是最常见的实现方式之一。其基本原理是:用户在登录系统A后,系统A会生成一个包含用户身份信息的Cookie,并将其存储在用户的浏览器中。当用户访问系统B时,系统B会检查用户浏览器中的Cookie,如果存在有效的Cookie,则允许用户访问系统B,而无需再次登录。
基于Token的单点登录是另一种常见的实现方式。其基本原理是:用户在登录系统A后,系统A会生成一个包含用户身份信息的Token,并将其返回给用户。当用户访问系统B时,系统B会检查用户携带的Token,如果Token有效,则允许用户访问系统B,而无需再次登录。
OAuth2.0是一种授权框架,广泛用于单点登录的实现。其基本原理是:用户通过授权服务器进行身份验证,授权服务器生成一个访问令牌(Access Token),用户可以使用该令牌访问多个资源服务器。
SAML(Security Assertion Markup Language)是一种基于XML的标准,用于在不同的安全域之间交换认证和授权数据。SAML协议通常用于企业级单点登录的实现。
在开始实现单点登录之前,我们需要准备以下环境:
首先,我们需要创建一个SpringBoot项目。可以使用Spring Initializr快速生成项目结构。
mvn archetype:generate -DgroupId=com.example -DartifactId=sso-demo -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
在pom.xml中添加Spring Security和OAuth2.0的依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
在application.yml中配置OAuth2.0授权服务器:
security:
oauth2:
client:
client-id: client
client-secret: secret
scope: read,write
authorized-grant-types: authorization_code,refresh_token,password
access-token-validity-seconds: 3600
refresh-token-validity-seconds: 86400
resource:
id: resource
创建一个SecurityConfig类,配置Spring Security:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/oauth/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().permitAll()
.and()
.logout().permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("{noop}password").roles("USER");
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
创建一个ResourceServerConfig类,配置OAuth2.0资源服务器:
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/**").authenticated();
}
}
启动项目后,访问http://localhost:8080/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://localhost:8080/login,输入用户名和密码进行登录。登录成功后,系统会生成一个授权码,并将其重定向到指定的redirect_uri。
在pom.xml中添加JWT的依赖:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
创建一个JwtUtil类,用于生成和验证JWT:
public class JwtUtil {
private static final String SECRET_KEY = "secret";
public static String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 3600000))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
public static String getUsernameFromToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
public static boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
return true;
} catch (Exception e) {
return false;
}
}
}
在SecurityConfig类中配置Spring Security,使用JWT进行身份验证:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/public/**").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("{noop}password").roles("USER");
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
创建一个JwtAuthenticationFilter类,用于处理JWT的验证:
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String token = request.getHeader("Authorization");
if (token != null && JwtUtil.validateToken(token)) {
String username = JwtUtil.getUsernameFromToken(token);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(request, response);
}
}
启动项目后,访问http://localhost:8080/api/public/login,输入用户名和密码进行登录。登录成功后,系统会生成一个JWT,并将其返回给用户。用户可以使用该JWT访问其他受保护的API。
在pom.xml中添加CAS的依赖:
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.6.0</version>
</dependency>
在application.yml中配置CAS客户端:
cas:
server-url: https://cas.example.org/cas
service-url: http://localhost:8080/login/cas
在SecurityConfig类中配置Spring Security,使用CAS进行身份验证:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login/cas").permitAll()
.anyRequest().authenticated()
.and()
.csrf().disable()
.addFilterBefore(casAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter filter = new CasAuthenticationFilter();
filter.setAuthenticationManager(authenticationManagerBean());
return filter;
}
@Bean
public CasAuthenticationProvider casAuthenticationProvider() {
CasAuthenticationProvider provider = new CasAuthenticationProvider();
provider.setServiceProperties(serviceProperties());
provider.setAuthenticationUserDetailsService(userDetailsService());
provider.setTicketValidator(cas20ServiceTicketValidator());
provider.setKey("casAuthProviderKey");
return provider;
}
@Bean
public ServiceProperties serviceProperties() {
ServiceProperties properties = new ServiceProperties();
properties.setService("http://localhost:8080/login/cas");
properties.setSendRenew(false);
return properties;
}
@Bean
public UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(Collections.singletonList(
User.withUsername("user").password("{noop}password").roles("USER").build()));
}
@Bean
public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
return new Cas20ServiceTicketValidator("https://cas.example.org/cas");
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
启动项目后,访问http://localhost:8080/login/cas,系统会将用户重定向到CAS服务器进行登录。登录成功后,CAS服务器会将用户重定向回应用,并允许用户访问受保护的资源。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。