文章目录
前言
shiro主张的是将主体的认证和权限管理交由用户自己定义,所以只需要自定以完realm后注入到securityManager就行
一、ShiroConfig 修改
修改securityManager方法
添加modularRealmAuthenticator方法
public class ShiroConfig {
/**
*
* SecurityManager 是 Shiro 架构的核心,通过它来链接Realm和用户(文档中称之为Subject.)
*
* @param appRealm
* @param desktopRealm
* @param userModularRealmAuthenticator 自定义 RealAuthenticator
* @return
*/
@Bean("securityManager")
public DefaultWebSecurityManager securityManager(@Qualifier("appRealm") AppRealm appRealm,
@Qualifier("desktopRealm") DesktopRealm desktopRealm,
@Qualifier("userModularRealmAuthenticator") UserModularRealmAuthenticator userModularRealmAuthenticator) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// securityManager.setRealm(myRealm);
securityManager.setAuthenticator(userModularRealmAuthenticator);
List<Realm> realms = new ArrayList<>();
//添加多个Realm
realms.add(desktopRealm);
realms.add(appRealm);
securityManager.setRealms(realms);
/*
* 关闭shiro自带的session,详情见文档
* http://shiro.apache.org/session-management.html#SessionManagement-
* StatelessApplications%28Sessionless%29
*/
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
securityManager.setSubjectDAO(subjectDAO);
//自定义缓存实现,使用redis
securityManager.setCacheManager(redisCacheManager());
return securityManager;
}
/**
* 系统自带的Realm管理,主要针对多realm
* */
@Bean
public ModularRealmAuthenticator modularRealmAuthenticator(){
//自己重写的ModularRealmAuthenticator
UserModularRealmAuthenticator modularRealmAuthenticator = new UserModularRealmAuthenticator();
modularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());//这里为默认策略:如果有一个或多个Realm验证成功,所有的尝试都被认为是成功的,如果没有一个验证成功,则该次尝试失败
return modularRealmAuthenticator;
}
}
二、复制ShiroRealm类
针对业务复制ShiroRealm类
并添加getName() 方法
@Component
@Slf4j
public class DesktopRealm extends AuthorizingRealm {
...
@Override
public String getName() {
return "Desktop";
}
...
@Component
@Slf4j
public class AppRealm extends AuthorizingRealm {
...
@Override
public String getName() {
return "App";
}
...
三、JwtFilter和JwtToken修改
@Slf4j
public class JwtFilter extends BasicHttpAuthenticationFilter {
...
@Override
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String token = httpServletRequest.getHeader(DefContants.X_ACCESS_TOKEN);
String loginType = httpServletRequest.getHeader(DefContants.X_LOGIN_TYPE);
JwtToken jwtToken = new JwtToken(token, loginType);
// 提交给realm进行登入,如果错误他会抛出异常并被捕获
getSubject(request, response).login(jwtToken);
// 如果没有抛出异常则代表登入成功,返回true
return true;
}
...
}
public class JwtToken implements AuthenticationToken {
private static final long serialVersionUID = 1L;
private String token;
// 增加
private String loginType;
public JwtToken(String token) {
this.token = token;
}
// 增加
public JwtToken(String token, String loginType) {
this.token = token;
this.loginType = loginType;
}
@Override
public Object getPrincipal() {
return token;
}
@Override
public Object getCredentials() {
return token;
}
public void setLoginType(String loginType) {
this.loginType = loginType;
}
public String getLoginType() {
return loginType;
}
}
四、增加UserModularRealmAuthenticator类
/**
*
* 当配置了多个Realm时,我们通常使用的认证器是shiro自带的
* org.apache.shiro.authc.pam.ModularRealmAuthenticator,
* 其中决定使用的Realm的是doAuthenticate()方法
*/
@Slf4j
@Component
public class UserModularRealmAuthenticator extends ModularRealmAuthenticator {
@Override
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
log.info("UserModularRealmAuthenticator:method doAuthenticate() 执行 ");
// 判断getRealms()是否返回为空
assertRealmsConfigured();
// 所有Realm
Collection<Realm> realms = getRealms();
JwtToken jwtToken = (JwtToken) authenticationToken;
String loginType = jwtToken.getLoginType();
// 增加默认
if(StrUtil.isEmpty(loginType)){
loginType = "App";
}
Realm realm = null;
for (Realm realmItem : realms) {
log.info("Realm>>>>{}", realmItem.getName());
log.info("Realm>>>>{}", loginType);
if (realmItem.getName().contains(loginType)) {
log.info("Realm>>{}", "Desktop请求");
realm = realmItem;
break;
}
if (realmItem.getName().contains(loginType)) {
log.info("Realm>>{}", "App端请求");
realm = realmItem;
break;
}
}
if(realm == null){
return null;
}
return doSingleRealmAuthentication(realm, authenticationToken);
}
}