Shiro认证
1. Shiro简介
Shiro是一个强大且灵活的Java安全框架,专注于认证、授权、加密、会话管理等功能,能够无缝集成到现有的应用程序中。相比Spring Security,Shiro的学习曲线较为平缓,配置简单
(1) Shiro特性
- 认证(Authentication):身份验证,确认用户的身份信息
- 授权(Authorization):基于角色或权限控制访问资源
- 会话管理(Session Management):支持JavaSE和JavaEE环境下的会话管理
- 加密(Cryptography):提供用于安全操作的加密API
- 易扩展性:Shiro的各个模块是解耦的,开发者可以根据需要进行灵活扩展
(2) Shiro架构
Shiro的核心架构主要由以下几部分组成:
- Subject:表示当前用户,包括已登录和未登录的用户
- SecurityManager:Shiro的核心控制器,管理所有安全操作,相当于Spring Security中的Filter Chain
- Realm:用于连接实际数据源(如数据库)和Shiro,负责根据用户凭证获取相应的权限、角色信息
2. 认证(Authentication)
认证是Shiro中的一个重要部分,主要验证用户的身份
(1) Token
Shiro中的认证是基于令牌(Token)的,最常用的令牌是UsernamePasswordToken
,它包含用户名和密码,用于在登录时进行身份验证
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.apache.shiro.authc;
public class UsernamePasswordToken implements HostAuthenticationToken, RememberMeAuthenticationToken {
private String username;
private char[] password;
private boolean rememberMe;
private String host;
public UsernamePasswordToken() {
this.rememberMe = false;
}
public UsernamePasswordToken(String username, char[] password) {
this(username, (char[])password, false, (String)null);
}
public UsernamePasswordToken(String username, String password) {
this(username, (char[])(password != null ? password.toCharArray() : null), false, (String)null);
}
public UsernamePasswordToken(String username, char[] password, String host) {
this(username, password, false, host);
}
public UsernamePasswordToken(String username, String password, String host) {
this(username, password != null ? password.toCharArray() : null, false, host);
}
public UsernamePasswordToken(String username, char[] password, boolean rememberMe) {
this(username, (char[])password, rememberMe, (String)null);
}
public UsernamePasswordToken(String username, String password, boolean rememberMe) {
this(username, (char[])(password != null ? password.toCharArray() : null), rememberMe, (String)null);
}
public UsernamePasswordToken(String username, char[] password, boolean rememberMe, String host) {
this.rememberMe = false;
this.username = username;
this.password = password;
this.rememberMe = rememberMe;
this.host = host;
}
public UsernamePasswordToken(String username, String password, boolean rememberMe, String host) {
this(username, password != null ? password.toCharArray() : null, rememberMe, host);
}
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
public char[] getPassword() {
return this.password;
}
public void setPassword(char[] password) {
this.password = password;
}
public Object getPrincipal() {
return this.getUsername();
}
public Object getCredentials() {
return this.getPassword();
}
public String getHost() {
return this.host;
}
public void setHost(String host) {
this.host = host;
}
public boolean isRememberMe() {
return this.rememberMe;
}
public void setRememberMe(boolean rememberMe) {
this.rememberMe = rememberMe;
}
public void clear() {
this.username = null;
this.host = null;
this.rememberMe = false;
if (this.password != null) {
for(int i = 0; i < this.password.length; ++i) {
this.password[i] = 0;
}
this.password = null;
}
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getName());
sb.append(" - ");
sb.append(this.username);
sb.append(", rememberMe=").append(this.rememberMe);
if (this.host != null) {
sb.append(" (").append(this.host).append(")");
}
return sb.toString();
}
}
(2) 认证流程
Shiro的认证流程如下:
- 用户提交身份认证请求,通常为登录操作
- Shiro将用户信息封装为
Token
Subject.login(token)
方法调用,将Token传递给SecurityManager- SecurityManager通过
Realm
查找用户信息并验证凭证 - 验证通过后,Shiro会将用户的信息存储到会话中
(3) 记住我VS认证
- 认证:用户成功登录并创建会话,Session管理用户的登录状态
- 记住我:用户选择"记住我"功能后,即使关闭浏览器,用户信息也能在下次访问时恢复,但不一定是完全的会话恢复。Shiro通过Cookie机制实现这一点
(4) 注销Logout
注销操作通过Subject.logout()
方法实现。Shiro会自动清除Session,并将相关的登录信息从SecurityManager
中移除
SecurityUtils.getSubject().logout();//shiro再注销一下
3. SpringBoot+Shiro认证
在SpringBoot项目中集成Shiro非常简单,只需进行少量配置即可实现认证功能
(1) 导入Shiro相关依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.8.0</version>
</dependency>
(2) 自定义Realm
自定义Realm
用于连接数据库进行身份认证和授权:
package com.ktjiaoyu.crm.config.shiro;
import com.ktjiaoyu.crm.pojo.User;
import com.ktjiaoyu.crm.service.UserService;
import jakarta.annotation.Resource;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
/**
* @Author: wangtao
* @CreateTime: 2024-10-16-19:07
* @Description: 自定义Realm
* @Version: 1.0
*/
public class MyShiroRealm extends AuthorizingRealm {
@Resource
private UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("调用MyShiroRealm.doGetAuthorizationInfo获取权限信息");
//获取权限信息
User user = (User) principalCollection.getPrimaryPrincipal();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//暂不授予权限信息,下章再搞授权
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("调用MyShiroRealm.doGetAuthorizationInfo获取身份信息!");
//获取身份信息
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String usrName = token.getUsername();
User user = userService.getUserByUsrName(usrName);
if(user == null){
throw new UnknownAccountException();//账号错误
}
if(user.getUsrFlag() == null || user.getUsrFlag().intValue() == 0){
throw new LockedAccountException();//账号锁定
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getUsrPassword(), getName());
//返回身份信息
return info;
}
}
(3) 配置Shiro相关对象
在SpringBoot中配置Shiro,包含SecurityManager
、过滤器和自定义Realm
:
package com.ktjiaoyu.crm.config.shiro;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.util.ThreadContext;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author: wangtao
* @CreateTime: 2024-10-16-19:15
* @Description: Shiro配置类
* @Version: 1.0
*/
@Configuration
public class ShiroConfig {
@Bean
public MyShiroRealm myShiroRealm(){//自定义Realm
MyShiroRealm myShiroRealm = new MyShiroRealm();
return myShiroRealm;
}
@Bean
public SecurityManager securityManager(){//安全管理器
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
ThreadContext.bind(securityManager);//加上这句代码手动绑定
//注入Realm
securityManager.setRealm(myShiroRealm());
return securityManager;
}
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
//shiro过滤器:权限认证
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//注入securityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
//权限验证:使用Filter控制资源(URL)的访问
return shiroFilterFactoryBean;
}
}
(4) 测试认证登录
配置好之后,可以通过以下方式测试登录功能:
//创建Realm(安全数据源)
IniRealm realm = new IniRealm("classpath:shiro.ini");
//通过shiro.ini配置文件 创建Realm
DefaultSecurityManager securityManager = new DefaultSecurityManager(realm);
//注入创建的Realm(安全数据源)
securityManager.setRealm(realm);
SecurityUtils.setSecurityManager(securityManager);
//进行认证
Subject subject = SecurityUtils.getSubject();
//封装令牌
UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");
try {
subject.login(token);
}catch (AuthenticationException e){
e.printStackTrace();
}
System.out.println("是否认证通过:"+subject.isAuthenticated());
System.out.println("身份信息:"+subject.getPrincipal());
原文地址:https://blog.csdn.net/Pre_W/article/details/142993768
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!