Shiro的理解
谨慎参考,出bug概不负责(本人菜鸟小白)
三部分 subject :主体(类似与对象),security Manager:安全管理器
Realm:域
shiro可以进行授权,认证和安全验证(一般用JWT),类似的东西有spring security。
主要用途就是拦截前端过来的请求(login register等除外),然后进行授权,认证等
package com.zyf.springcloud.config;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.Filter;
import com.zyf.springcloud.utils.JwtCredentialsMatcher;
import com.zyf.springcloud.utils.MultiRealmAuthenticator;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.pam.AuthenticationStrategy;
import org.apache.shiro.authc.pam.FirstSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.mgt.SessionStorageEvaluator;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.zyf.springcloud.config.filter.JwtFilter;
@Configuration
public class ShiroConfig {
/**
* 交由 Spring 来自动地管理 Shiro-Bean 的生命周期
*/
@Bean
public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**
* 为 Spring-Bean 开启对 Shiro 注解的支持
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator app = new DefaultAdvisorAutoProxyCreator();
app.setProxyTargetClass(true);
return app;
}
/**
* 不向 Spring容器中注册 JwtFilter Bean,防止 Spring 将 JwtFilter 注册为全局过滤器
* 全局过滤器会对所有请求进行拦截,而本例中只需要拦截除 /login 和 /logout 外的请求
* 另一种简单做法是:直接去掉 jwtFilter()上的 @Bean 注解
*/
@Bean
public FilterRegistrationBean<Filter> registration(JwtFilter filter) {
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<Filter>(filter);
registration.setEnabled(false);
return registration;
}
@Bean
public JwtFilter jwtFilter() {
return new JwtFilter();
}
/**
* 配置访问资源需要的权限
*/
@Bean
ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/authorized");
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
// 添加 jwt 专用过滤器,拦截除 /login 和 /logout 外的请求
Map<String, Filter> filterMap = new LinkedHashMap<>();
filterMap.put("jwtFilter", jwtFilter());
shiroFilterFactoryBean.setFilters(filterMap);
LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
filterChainDefinitionMap.put("/login", "anon"); // 可匿名访问
filterChainDefinitionMap.put("/logout", "logout"); // 退出登录
filterChainDefinitionMap.put("/**", "jwtFilter,authc"); // 需登录才能访问
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
/**
* 配置 ModularRealmAuthenticator
*/
@Bean
public ModularRealmAuthenticator authenticator() {
ModularRealmAuthenticator authenticator = new MultiRealmAuthenticator();
// 设置多 Realm的认证策略,默认 AtLeastOneSuccessfulStrategy
AuthenticationStrategy strategy = new FirstSuccessfulStrategy();
authenticator.setAuthenticationStrategy(strategy);
return authenticator;
}
/**
* 禁用session, 不保存用户登录状态。保证每次请求都重新认证
*/
@Bean
protected SessionStorageEvaluator sessionStorageEvaluator() {
DefaultSessionStorageEvaluator sessionStorageEvaluator = new DefaultSessionStorageEvaluator();
sessionStorageEvaluator.setSessionStorageEnabled(false);
return sessionStorageEvaluator;
}
/**
* JwtRealm 配置,需实现 Realm 接口
*/
@Bean
JwtRealm jwtRealm() {
JwtRealm jwtRealm = new JwtRealm();
// 设置加密算法
CredentialsMatcher credentialsMatcher = new JwtCredentialsMatcher();
// 设置加密次数
jwtRealm.setCredentialsMatcher(credentialsMatcher);
return jwtRealm;
}
/**
* ShiroRealm 配置,需实现 Realm 接口
*/
@Bean
ShiroRealm shiroRealm() {
ShiroRealm shiroRealm = new ShiroRealm();
// 设置加密算法
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher("SHA-1");
// 设置加密次数
credentialsMatcher.setHashIterations(16);
shiroRealm.setCredentialsMatcher(credentialsMatcher);
return shiroRealm;
}
/**
* 配置 SecurityManager
*/
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 1.Authenticator
securityManager.setAuthenticator(authenticator());
// 2.Realm
List<Realm> realms = new ArrayList<Realm>(16);
realms.add(jwtRealm());
realms.add(shiroRealm());
securityManager.setRealms(realms);
// 3.关闭shiro自带的session
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
subjectDAO.setSessionStorageEvaluator(sessionStorageEvaluator());
securityManager.setSubjectDAO(subjectDAO);
return securityManager;
}
}
在这里插入代码片package com.zyf.springcloud.config;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.zyf.springcloud.utils.UserEntity;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
/**
* 同时开启身份验证和权限验证,需要继承 AuthorizingRealm
* 并实现其 doGetAuthenticationInfo()和 doGetAuthorizationInfo 两个方法
*/
@SuppressWarnings("serial")
public class ShiroRealm extends AuthorizingRealm {
public static Map<String, UserEntity> userMap = new HashMap<String, UserEntity>(16);
public static Map<String, Set<String>> roleMap = new HashMap<String, Set<String>>(16);
public static Map<String, Set<String>> permMap = new HashMap<String, Set<String>>(16);
static {
UserEntity user1 = new UserEntity(1L, "graython", "dd524c4c66076d1fa07e1fa1c94a91233772d132", "灰先生", false);
UserEntity user2 = new UserEntity(2L, "plum", "cce369436bbb9f0325689a3a6d5d6b9b8a3f39a0", "李先生", false);
userMap.put("graython", user1);
userMap.put("plum", user2);
roleMap.put("graython", new HashSet<String>() {
{
add("admin");
}
});
roleMap.put("plum", new HashSet<String>() {
{
add("guest");
}
});
permMap.put("plum", new HashSet<String>() {
{
add("article:read");
}
});
}
/**
* 限定这个 Realm 只处理 UsernamePasswordToken
*/
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof UsernamePasswordToken;
}
/**
* 查询数据库,将获取到的用户安全数据封装返回
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 从 AuthenticationToken 中获取当前用户
String username = (String) token.getPrincipal();
// 查询数据库获取用户信息,此处使用 Map 来模拟数据库
UserEntity user = userMap.get(username);
// 用户不存在
if (user == null) {
throw new UnknownAccountException("用户不存在!");
}
// 用户被锁定
if (user.getLocked()) {
throw new LockedAccountException("该用户已被锁定,暂时无法登录!");
}
// 使用用户名作为盐值
ByteSource credentialsSalt = ByteSource.Util.bytes(username);
/**
* 将获取到的用户数据封装成 AuthenticationInfo 对象返回,此处封装为 SimpleAuthenticationInfo 对象。
* 参数1. 认证的实体信息,可以是从数据库中获取到的用户实体类对象或者用户名
* 参数2. 查询获取到的登录密码
* 参数3. 盐值
* 参数4. 当前 Realm 对象的名称,直接调用父类的 getName() 方法即可
*/
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), credentialsSalt,
getName());
return info;
}
/**
* 查询数据库,将获取到的用户的角色及权限信息返回
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 获取当前用户
UserEntity currentUser = (UserEntity) SecurityUtils.getSubject().getPrincipal();
// UserEntity currentUser = (UserEntity)principals.getPrimaryPrincipal();
// 查询数据库,获取用户的角色信息
Set<String> roles = roleMap.get(currentUser.getName());
// 查询数据库,获取用户的权限信息
Set<String> perms = permMap.get(currentUser.getName());
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setRoles(roles);
info.setStringPermissions(perms);
return info;
}
}