本文目录导读:
图片来源于网络,如有侵权联系删除
Shiro SSO单点登录教程
单点登录(SSO)概述
单点登录(Single Sign - On,SSO)是一种身份验证机制,允许用户使用一组凭据(如用户名和密码)登录到多个相关但独立的应用程序,在企业级应用中,这一技术极大地提高了用户体验,减少了用户需要记住多个账号密码的麻烦,同时也方便了系统管理员进行统一的用户管理和权限控制。
Shiro简介
Apache Shiro是一个强大且易用的Java安全框架,它提供了身份验证、授权、加密和会话管理等功能,Shiro的架构清晰,易于集成到现有的Java应用中,使其成为实现SSO单点登录的理想选择。
基于Shiro实现SSO单点登录的步骤
(一)创建Shiro核心配置
1、引入依赖
- 在项目的pom.xml
(如果是Maven项目)中引入Shiro相关依赖。
```xml
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro - core</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro - web</artifactId>
<version>1.7.1</version>
</dependency>
```
2、配置Shiro核心组件
- 创建shiro.ini
(对于简单配置)或者通过Java代码配置ShiroFilterFactoryBean
、SecurityManager
等核心组件。
- 在Java配置中:
```java
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 配置过滤链规则等
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置Realm等
securityManager.setRealm(myRealm());
return securityManager;
}
@Bean
public MyRealm myRealm() {
return new MyRealm();
}
}
```
(二)实现单点登录的关键逻辑
1、共享会话管理
- 在多应用场景下,需要一个共享的会话存储机制,可以使用分布式缓存(如Redis)来存储会话信息。
- 集成Shiro与Redis,例如通过shiro - redis
插件。
图片来源于网络,如有侵权联系删除
- 配置RedisManager
和RedisSessionDAO
:
```java
@Bean
public RedisManager redisManager() {
RedisManager redisManager = new RedisManager();
redisManager.setHost("localhost");
redisManager.setPort(6379);
return redisManager;
}
@Bean
public RedisSessionDAO redisSessionDAO() {
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisManager(redisManager());
return redisSessionDAO;
}
```
- 在SecurityManager
中设置SessionManager
并使用RedisSessionDAO
:
```java
@Bean
public DefaultWebSessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionDAO(redisSessionDAO());
return sessionManager;
}
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm());
securityManager.setSessionManager(sessionManager());
return securityManager;
}
```
2、跨域身份验证处理
- 当涉及到多个不同域名的应用进行单点登录时,需要处理跨域问题。
- 在Shiro中,可以通过设置CORS(跨域资源共享)相关的过滤器来允许跨域请求携带认证信息。
- 创建一个自定义的CorsFilter
:
```java
public class CorsFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
response.setHeader("Access - Control - Allow - Origin", "*");
response.setHeader("Access - Control - Allow - Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access - Control - Max - Age", "3600");
response.setHeader("Access - Control - Allow - Headers", "authorization, content - type");
filterChain.doFilter(request, response);
}
}
```
- 并在ShiroFilterFactoryBean
的过滤链中添加这个CorsFilter
:
```java
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
图片来源于网络,如有侵权联系删除
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/**", "authc");
// 添加CorsFilter
Map<String, Filter> filters = new HashMap<>();
filters.put("corsFilter", new CorsFilter());
shiroFilterFactoryBean.setFilters(filters);
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
```
3、统一登录与登出逻辑
登录逻辑
- 在登录接口中,通过Shiro的Subject
进行身份验证。
```java
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginDTO loginDTO) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(loginDTO.getUsername(), loginDTO.getPassword());
try {
subject.login(token);
// 登录成功后,可以返回一些必要的信息,如用户信息、令牌等
return ResponseEntity.ok("登录成功");
} catch (AuthenticationException e) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("用户名或密码错误");
}
}
```
登出逻辑
- 在登出接口中,同样通过Subject
进行登出操作。
```java
@PostMapping("/logout")
public ResponseEntity<?> logout() {
Subject subject = SecurityUtils.getSubject();
if (subject.isAuthenticated()) {
subject.logout();
}
return ResponseEntity.ok("登出成功");
}
```
测试单点登录
1、启动多个应用
- 假设我们有两个不同的Java Web应用,分别为App1
和App2
,都集成了上述的Shiro SSO单点登录配置。
2、登录测试
- 首先访问App1
的登录页面,输入正确的用户名和密码进行登录,登录成功后,在不重新登录的情况下,直接访问App2
的受保护页面,如果能够成功访问,说明单点登录成功。
3、登出测试
- 在App2
中点击登出按钮,然后再访问App1
的受保护页面,此时应该被重定向到登录页面,说明登出操作在单点登录环境下正常工作。
通过以上步骤,我们可以基于Shiro框架成功实现SSO单点登录,提高用户体验并方便系统管理,在实际应用中,还可以根据具体的业务需求进一步优化和扩展,如集成更多的身份验证方式(如第三方登录)等。
评论列表