import java.util.ArrayList;
import java.util.Collection;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.realm.Realm;
/**
* CustomizedModularRealmAuthenticator
* 多Realm验证模块
*/
public class CustomizedModularRealmAuthenticator extends ModularRealmAuthenticator {
@Override
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken)
throws AuthenticationException {
// 判断getRealms()是否返回为空
assertRealmsConfigured();
// CustomizedToken
CustomizedToken customizedToken = (CustomizedToken) authenticationToken;
// 登录类型
String loginType = customizedToken.getLoginType();
// 所有Realm
Collection<Realm> realms = getRealms();
// 登录类型对应的所有Realm
Collection<Realm> typeRealms = new ArrayList<>();
for (Realm realm : realms) {
//可以修改此规则来匹配你的登录类型
if (realm.getName().contains(loginType)) {
typeRealms.add(realm);
}
}
if (typeRealms.size() == 1) {
//单Realm
return doSingleRealmAuthentication(typeRealms.iterator().next(), customizedToken);
}
else {
//多Realm
return doMultiRealmAuthentication(typeRealms, customizedToken);
}
}
}
import org.apache.shiro.authc.UsernamePasswordToken;
public class CustomizedToken extends UsernamePasswordToken {
//登录类型
private String loginType;
public CustomizedToken(final String username, final String password,String loginType) {
super(username,password);
this.loginType = loginType;
}
public String getLoginType() {
return loginType;
}
public void setLoginType(String loginType) {
this.loginType = loginType;
}
}
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hwx.api.entity.StoreUser;
import com.hwx.api.entity.SysUser;
import com.hwx.api.service.IMiniappConfigService;
import com.hwx.api.service.IStoreUserService;
import com.hwx.util.Const;
import com.hwx.util.Jurisdiction;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import javax.annotation.Resource;
public class ShiroRealmMini extends AuthorizingRealm {
@Resource
IStoreUserService iStoreUserService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取用户的输入的账号.
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
String username = usernamePasswordToken.getUsername();
String password = String.valueOf(usernamePasswordToken.getPassword());
//根据用户名查询,用户名必须是唯一
QueryWrapper<StoreUser> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("openId", username);
StoreUser storeUser = iStoreUserService.getOne(queryWrapper);
/*校验密码*/
/*加密方式*/
String algorithmName = "MD5";
/*加密次数*/
int hashIterations = 2000;
/*加密盐值 username作为颜值必须为唯一值 注册时需要注意*/
Object salt = ByteSource.Util.bytes(storeUser.getUnionId());
/*md5Result:9ec808d39c36c800591f1ee14f5f3175*/
String md5Result = new SimpleHash("MD5", password, salt, hashIterations).toHex();
/*判断用户密码是否正确,状态等*/
if (storeUser != null) {
if (md5Result.equals(storeUser.getPassword())) {
/*session用户*/
Session session = Jurisdiction.getSession();
session.setAttribute(username + Const.SESSION_USER,storeUser);
/*通过身份验证*/
/*principal:认证信息,可以是username,也可以是整个实体*/
Object principal = storeUser;
/*credentials:密码*/
Object credentials = storeUser.getPassword();
/*credentialsSalt:盐值*/
ByteSource credentialsSalt = ByteSource.Util.bytes(storeUser.getUnionId());
/*realmName:当前realm对象的name,调用父类getName()*/
String realmName = getName();
SimpleAuthenticationInfo simpleAuthorizationInfo = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);
return simpleAuthorizationInfo;
}
}
return null;
}
}
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import java.util.*;
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
System.out.println("ShiroConfiguration.shirFilter()");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
/*拦截器*/
Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
/*配置不会被拦截的链接 顺序判断*/
/*anon:所有url都都可以匿名访问*/
/*webjars swagger 加载到webjar的资源,所以webjar下的资源不能被拦截,否者无法访问*/
filterChainDefinitionMap.put("/webjars/**", "anon");
filterChainDefinitionMap.put("/swagger-ui.html", "anon");
filterChainDefinitionMap.put("/swagger-resources/**", "anon");
filterChainDefinitionMap.put("/v2/api-docs/**", "anon");
filterChainDefinitionMap.put("/app/**", "anon");
filterChainDefinitionMap.put("/D://uploadfile/**", "anon");
/*配置退出*/
filterChainDefinitionMap.put("/logout", "logout");
filterChainDefinitionMap.put("/api/user/login", "anon");
filterChainDefinitionMap.put("/api/user/minilogin", "anon");
filterChainDefinitionMap.put("/api/file/fileUpload", "anon");
filterChainDefinitionMap.put("/index", "anon");
/*过滤链定义,从上向下顺序执行,一般将/**放在最为下*/
/*authc:所有url都必须认证通过才可以访问-->*/
filterChainDefinitionMap.put("/**", "authc");
/*如果不设置默认会自动寻找Web工程根目录下的"/login"页面*/
shiroFilterFactoryBean.setLoginUrl("/app/admin/index.html");
/* 登录成功后要跳转的链接*/
shiroFilterFactoryBean.setSuccessUrl("/userInfo");
/*未授权界面*/
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
/**
* 系统自带的Realm管理,主要针对多realm
* */
@Bean
public ModularRealmAuthenticator modularRealmAuthenticator(){
//自己重写的ModularRealmAuthenticator
CustomizedModularRealmAuthenticator customizedModularRealmAuthenticator = new CustomizedModularRealmAuthenticator();
customizedModularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
return customizedModularRealmAuthenticator;
}
/**
* 凭证匹配器(由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了)
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5"); //散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(2000); //散列的次数,比如散列两次,相当于 md5(md5(""));
return hashedCredentialsMatcher;
}
@Bean
public ShiroRealmPC ShiroRealmPC(){
ShiroRealmPC shiroRealmPC = new ShiroRealmPC();
shiroRealmPC.setCredentialsMatcher(hashedCredentialsMatcher());
return shiroRealmPC;
}
@Bean
public ShiroRealmMini ShiroRealmMini(){
ShiroRealmMini shiroRealmMini = new ShiroRealmMini();
shiroRealmMini.setCredentialsMatcher(hashedCredentialsMatcher());//设置解密规则
return shiroRealmMini;
}
@Bean
public SecurityManager securityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setAuthenticator(modularRealmAuthenticator());
List<Realm> realms = new ArrayList<>();
//添加多个Realm
realms.add(ShiroRealmPC());
realms.add(ShiroRealmMini());
securityManager.setRealms(realms);
// 自定义缓存实现 使用redis
//securityManager.setCacheManager(cacheManager());
// 自定义session管理 使用redis
//securityManager.setSessionManager(sessionManager());
//注入记住我管理器;
//securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}
/**
* 开启shiro aop注解支持.
* 使用代理方式;所以需要开启代码支持;
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean(name="simpleMappingExceptionResolver")
public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() {
SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理
mappings.setProperty("UnauthorizedException","403");
r.setExceptionMappings(mappings); // None by default
r.setDefaultErrorView("error"); // No default
r.setExceptionAttribute("ex"); // Default is "exception"
r.setWarnLogCategory("example.MvcLogger"); // No default
return r;
}
}
- 自定义CustomizedModularRealmAuthenticator 并继承 ModularRealmAuthenticator
- 自定义CustomizedToken 并继承 UsernamePasswordToken
- 自定义ShiroRealmMini ,可以写很多很多个这样的Realm
- ShiroConfig 中配置 ShiroRealmMini等Realm
- 然后就可以了