Shiro安全框架基础入门使用
2024-01-02 17:28:38
Shiro的核心功能
- Authentication 认证登录
- Authorization 授权、权限验证
- Session Management 会话管理
- Cryptography 加/解密
Shiro 的核心架构
- Authenticator 认证器
- Authorizer 授权器
- Session Manager 会话管理器
- Cache Manager 缓存控制器
- Session DAO 会话数据访问接口
- Realm 连接数据源,提供认证,授权、令牌等信息
- Cryptography 加/解密
SpringBoot整合Shiro
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.9.0</version>
<dependency>
配置文件
- shiro.ini
- application.yml shiro:
登录认证:
- 自定义Bean类型MyRealm继承自AuthorizingRealm类,并重写实现doGetAuthenticationInfo(AuthenticationToken authenticationToken)方法
- 获取用户身份信息
- String name = authenticationToken.getPrincipal().toString();
- 业务层查询数据库获取用户信息
- User user = userService.getUserInfoByName(name);
- 非空判断,将数据封装返回 if(user!=null){
- AuthenticationInfo info = new SimpleAuthenticationInfo(authenticationToken.getPrncipal,user.getPwd(),ByteSource.Util.bytes(“salt值”),authenticationToken.getPrincipal.toString());
- return info;
public class MyRealm extends AuthorizingRealm{
@Autowired
private UserService userService;
//自定义登录认证方法
@override
public AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken){
String name = authenticationToken.getPrincipal().toString();
User user = userService.getUserInfoByName(name);
if(user!=null){
//ByteSource.Util.bytes("salt值"),密码明文加密时拼接的盐值
AuthenticationInfo info = new SimpleAuthenticationInfo(authenticationToken.getPrncipal,user.getPwd(),ByteSource.Util.bytes("salt值"),authenticationToken.getPrincipal.toString());
return info;
}
}
}
配置类ShiroConfig:
@Configuration
public class ShiroConfig {
@Autowired
private MyRealm myRealm;
//配置SecurityManager,加密与密码匹配
@Bean
public DefaultWebSecurityManager defaultWebSecurityManager(){
//1创建defaultWebSecurityManager 对象
DefaultWebSecurityManager dwsm = new DefaultWebSeccurityManager();
//2创建加密对象,设置相关属性
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
//2.1 采用MD5算法加密
matcher.setHashAlgorithmName("md5);
//2.2 迭代加密次数
matcher.setHashIterations(3);
//3将加密对象存储到myRealm中,用于比对用户输入的密码与存储的是否一致
myRealm.setCredentialsMatcher(matcher);
//4将myRealm存入defaultWebSecurityManager对象
dwsm.setRealm(myRealm);
//5返回
return dwsm;
}
//配置Shiro内置过滤器拦截范围
@Bean
public DefaultShiroFilterChainDefinition shiroFilterChainDefinition(){
DefaultShiroFilterChainDefinition definition = new DefaultShiroFilterChainDefinition();
//配置不认证可以访问的资源 "anon",匿名用户,表示不需要认证
definition.addPathDefinition("/myController/userLogin","anon");
definition.addPathDefinition("/login","anon");
//配置需要进行登录认证的拦截范围 "authc",需要进行身份验证的用户,表示需要进行登录认证。
definition.addPathDefinition("/**","authc");
// 通过rememberMe不拦截,"user",已登录的用户,表示允许通过 rememberMe 功能进行身份验证的用户。
definition.addPathDefinition("/**","user");
// 配置登出,"logout",登出过滤器,表示用于处理用户登出的请求。
definition.addPathDefinition("/logout","logout");
return definition;
}
}
addPathDefinition() 方法的第二个参数是拦截器链中的一个过滤器(Filter),它将应用于与指定路径匹配的所有请求。
登录:
public String login(String name,String passwd,boolean rememberMe){
Subject subject = SecurityUtils.getSubject();
AuthenticationToken token = new UsernamePasswordToken(name,passwd,rememberMe);
try{
//登录
subject.login(token);
//登出
//subject.logout();
return "登陆成功";
}catch(AuthenticationException e){
e.printStackTrace();
return "登陆失败";
}
Realm认证策略
- AtLeastOneSuccessfulStrategy 只要有一个Realm验证成功,就视为认证成功(默认)
- FirstSuccessfulStrategy 第一个Realm认证成功,就视为认证成功,后面的Realm忽略验证
- AllSuccessfulStrategy 全部Realm认证成功,才视为成功
实现:
在ShiroConfig类配置SecurityManager时,
ModularRealmAuthenticator modularRealmAuthenticator = new ModularRealmAuthenticator();
//设置认证策略 AllSuccessfulStrategy
modularRealmAuthenticator.setAuthenticationStrategy(new AllSuccessfulStrategy());
dwsm.setAuthenticator(modularRealmAuthenticator);
//封装myRealm集合
List<Realm> list = new ArrayList<>();
list.add(myRealm);
list.add(myRealm2);
//将myRealm存入defaultWebSecurityManager
dwsm.setRealms(list);
return dwsm;
remember me
配置类ShiroConfig中配置
//配置defaultWebSecurityManager中添加
dwsm.setRememberMeManager(rememberMeManager());
//cookie 属性设置
public SimleCookie rememberMeCookie(){
SimleCookie cookie = new SimpleCookie("rememberMe");
//设置跨域
//cookie.setDomain(domain);
cookie.setPath("/");
cookie.setHttpOnly(true);
cookie.setMaxAge(30*24*60*60);
return cookie;
}
//创建Shiro的cookie管理对象
public CookieRememberMeManager rememberMeManager(){
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
cookieRememberMeManager.setCipherKey("RememberMe的16位的Key的Cookie数据加密密钥".getBytes());
return cookieRememberMeManager;
}
登出
在配置类ShiroConfig中的过滤器配置方法shiroFilterChainDefinition()
中添加配置
//登出
definition.addPathDefinition("/logout","logout");
授权
自定义授权方法
获取当前登录用户的角色、权限信息,返回给shiro用来进行授权认证
- myRealm继承AuthorizingRealm并重写doGetAuthorizationInfo(PrincipalCollection principalCollection)方法
- 创建对象,封装当前登录用户的角色、权限信息
- SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
- 获取当前用户的身份信息
- String principal = principalCollection.getPrimaryPrincipal().toString();
- 调用业务层从数据库查询用户的角色信息
- List roles = userService.getUserRoleInfo(principal);
- 调用业务层从数据库查询用户的角色信息
- List permissions= userService.getUserPermissionInfo(roles);
- 存储角色
- info.addRoles(roles);
- 存储权限
- info.addStringPermissions(permissions);
- 返回信息
- return info;
public class MyRealm extends AuthorizingRealm{
@Autowired
private UserService userService;
//自定义授权方法
@override
public SimpleAuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection){
//创建对象,封装当前登录用户的角色、权限信息
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//获取当前用户的身份信息
String principal = principalCollection.getPrimaryPrincipal().toString();
List<String> roles = userService.getUserRoleInfo(principal);
List<String> permissions= userService.getUserPermissionInfo(roles);
info.addRoles(roles);
info.addStringPermissions(permissions);
return info;
}
}
}
默认授权注解@RequiresXXX()
- @RequiresAuthentication
- 验证用户是否登录,等同于方法subject.isAuthenticated()
- @RequiresUser
- 验证用户是否被记忆:
- 登录认证成功subject.isAuthenticated()为true
- 登录后被记忆subject.isRemembered()为true
- 验证用户是否被记忆:
- @RequiresGuest
- 验证是否是一个guest请求,是否是游客的请求
- 此时subject.getPrincipal()为null
- @RequiresRoles
- 验证subject是否有相应角色,有角色访问方法,没有则会抛出异常AuthorizationException。
- 例如:@RequiresRoles(“aRoleName”)
- void someMethod();
- 只有subject有aRoleName角色才能访问someMethod()方法
- @RequiresPermissions
- 验证subject是否有相应权限,有权限方法,没有则会抛出异常AuthorizationException。
- 例如:@RequiresPermissions(“file:read”,“write:aFile.txt”)
- void someMethod();
- subject必须同时含有file:read 和 write:aFile.txt权限才能访问方法someMethod();
注解可以添加在类、方法、字段上,一般在Controller方法上
启用 Shiro 注解支持
- 在 Spring Boot 主类中,添加 @EnableAspectJAutoProxy 和 @EnableWebMvc 注解,并添加一个名为 “org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor” 的 Bean,以启用 Shiro 注解的 AOP 支持。
@SpringBootApplication
@EnableAspectJAutoProxy
@EnableWebMvc
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
}
异常处理
- UnauthorizedException 无权限
- AuthorizationException 权限认证失败
@ControllerAdvice
public class PermissionsException{
@ResponseBody
@ExceptionHandler(UnauthorizedException.class)
public String unauthorizedException(Exception ex){
return "无权限";
}
@ResponseBody
@ExceptionHandler(AuthorizationException.class)
public String authorizationException(Exception ex){
return "权限认证失败";
}
}
文章来源:https://blog.csdn.net/lx5210521/article/details/135326403
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!