
以後一般繼承 AuthorizingRealm(授權)即可;其繼承了 AuthenticatingRealm(即身份驗證),而且也間接繼承了 CachingRealm(帶有緩存實作)
package com.baizhi.springboot_shiro.shiro.realms;
import com.baizhi.springboot_shiro.entity.Perms;
import com.baizhi.springboot_shiro.entity.Role;
import com.baizhi.springboot_shiro.entity.User;
import com.baizhi.springboot_shiro.service.UserService;
import com.baizhi.springboot_shiro.shiro.salt.MyByteSource;
import com.baizhi.springboot_shiro.utils.ApplicationContextUtil;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import java.util.List;
public class CustomerRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("調用授權驗證");
//擷取身份資訊
String primaryPrincipal = (String) principals.getPrimaryPrincipal();
//根據主審分資訊擷取角色和權限
UserService userService = (UserService) ApplicationContextUtil.getBean("userService");
User user = userService.findRolesByUserName(primaryPrincipal);
if (!CollectionUtils.isEmpty(user.getRoles())){
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
user.getRoles().forEach(role -> {
simpleAuthorizationInfo.addRole(role.getName());
//權限資訊
List<Perms> perms = userService.findPermsByRoleId(role.getId());
if (!CollectionUtils.isEmpty(perms)){
perms.forEach(perm -> {
simpleAuthorizationInfo.addStringPermission(perm.getName());
});
}
});
return simpleAuthorizationInfo;
}
// if ("xiaochen".equals(primaryPrincipal)){
// SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
// simpleAuthorizationInfo.addRole("admin");
// return simpleAuthorizationInfo;
// }
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String principal = (String) token.getPrincipal();
UserService userService = (UserService) ApplicationContextUtil.getBean("userService");
User user = userService.findByUsername(principal);
if (!ObjectUtils.isEmpty(user)) {
// SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), new MyByteSource(user.getSalt()), this.getName());
return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(), new MyByteSource(user.getSalt()),this.getName());
}
return null;
}
}
- 自定義Realm繼承AuthorizingRealm
- 使用doGetAuthenticationInfo方法經行認證
- 通過傳入的token擷取principal使用者名
- 使用principal查找資料庫擷取user對象
- 調用SimpleAuthenticationInfo方法構造SimpleAuthenticationInfo對象并且傳回
- 最後自定義的Realm的父類AuthenticatingRealm執行getAuthenticationInfo方法中的assertCredentialsMatch進行密碼驗證
public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
AuthenticationInfo info = getCachedAuthenticationInfo(token);
if (info == null) {
//otherwise not cached, perform the lookup:
info = doGetAuthenticationInfo(token);
log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info);
if (token != null && info != null) {
cacheAuthenticationInfoIfPossible(token, info);
}
} else {
log.debug("Using cached authentication info [{}] to perform credentials matching.", info);
}
if (info != null) {
assertCredentialsMatch(token, info);
} else {
log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}]. Returning null.", token);
}
return info;
}
protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {
CredentialsMatcher cm = getCredentialsMatcher();
if (cm != null) {
if (!cm.doCredentialsMatch(token, info)) {
//not successful - throw an exception to indicate this:
String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials.";
throw new IncorrectCredentialsException(msg);
}
} else {
throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify " +
"credentials during authentication. If you do not wish for credentials to be examined, you " +
"can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance.");
}
}
身份認證流程
流程如下:
首先調用 Subject.login(token) 進行登入,其會自動委托給 Security Manager,調用之前必須通過 SecurityUtils.setSecurityManager() 設定;
SecurityManager 負責真正的身份驗證邏輯;它會委托給 Authenticator 進行身份驗證;
Authenticator 才是真正的身份驗證者,Shiro API 中核心的身份認證入口點,此處可以自定義插入自己的實作;
Authenticator 可能會委托給相應的 AuthenticationStrategy 進行多 Realm 身份驗證,預設 ModularRealmAuthenticator 會調用 AuthenticationStrategy 進行多 Realm 身份驗證;
Authenticator 會把相應的 token 傳入 Realm,從 Realm 擷取身份驗證資訊,如果沒有傳回 / 抛出異常表示身份驗證成功了。此處可以配置多個 Realm,将按照相應的順序及政策進行通路。
參考他人的方法
https://blog.csdn.net/a739260008/article/details/108457418
參考他人的csdn添加連結描述