Shiro的登錄
以下代碼是一段簡單的shiro登錄代碼
@RequestMapping(value = "/subLogin",method = RequestMethod.POST)
@ResponseBody
public String subLogin(SubLoginForm subLoginForm){
Subject subject = SecurityUtils.getSubject();
if(subject.isAuthenticated()){
System.out.println("已經登錄,無需再次登錄");
return "redirect:index.html";
}
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(subLoginForm.getUsername(),subLoginForm.getPassword());
try{
if(subLoginForm.getRememberMe() != null){
usernamePasswordToken.setRememberMe(subLoginForm.getRememberMe());
}
subject.login(usernamePasswordToken);
}catch (AuthenticationException e){
e.printStackTrace();
}
if(subject.hasRole("admin")){
return "有admin權限";
}
return "無admin權限";
}
在這一段代碼中,我要分析一下subject.login(usernamePasswordToken);這一步
以下是個人現階段的見解,如有不正確請指出!
任意一個系統,集成shiro的時候,關於用戶,角色,權限等,基本都會用自定義表結構,所以我們需要自定義realm,來和數據庫交互。如圖所示:
在realm中,從自定義的用戶表中,查詢出來用戶信息,用來校驗用戶本次是否登錄成功。
以下代碼是一個自定義的realm
package com.imooc.shiro.realm;
import cn.hutool.core.collection.CollUtil;
import com.imooc.dao.UserDao;
import com.imooc.vo.User;
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 javax.annotation.Resource;
import java.util.HashSet;
import java.util.Set;
/**
* @author jianxinkuan
* @date 2020/3/15 18:53
*/
public class CustomRealm extends AuthorizingRealm {
@Resource
private UserDao userDao;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//1、獲取登錄用戶名
String userName = (String) principalCollection.getPrimaryPrincipal();
//2、通過用戶名獲取角色
Set<String> roleSet = getRolesByUserName(userName);
//3、根據用戶名獲取權限
Set<String> permissionSet = getPermissionsByUserName(userName);
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//設置角色
simpleAuthorizationInfo.setRoles(roleSet);
//設置權限
simpleAuthorizationInfo.setStringPermissions(permissionSet);
return simpleAuthorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//1、從認證主體中獲取用戶名
String userName = (String) authenticationToken.getPrincipal();
//2、通過用戶名從數據庫庫中檢索用戶
User user = getPasswordByUserName(userName);
if(user == null){
return null;
}
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userName, user.getPassword(), "admin");
//可以在這裏加鹽值
// simpleAuthenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("JXK"));
return simpleAuthenticationInfo;
}
/**
* 根據用戶名獲取權限
* @param userName
*/
private Set<String> getPermissionsByUserName(String userName) {
System.out.println("從數據庫獲取權限信息");
userDao.queryRolesByUserName(userName);
Set<String> permissionSet = new HashSet<>();
permissionSet.add("user:add");
permissionSet.add("user:delete");
permissionSet.add("user:update");
permissionSet.add("user:list");
return permissionSet;
}
/**
* 根據用戶名獲取角色
* @param userName
* @return
*/
private Set<String> getRolesByUserName(String userName) {
System.out.println("從數據庫獲取角色信息");
return CollUtil.newHashSet(userDao.queryRolesByUserName(userName));
}
/**
* 數據庫中檢索用戶信息
* @param userName
* @return
*/
private User getPasswordByUserName(String userName) {
return userDao.getUserByUserName(userName);
}
}
如代碼所示,自定義realm,我們需要繼承AuthorizingRealm 類,重新兩個方法
- doGetAuthorizationInfo
此方法內實現授權邏輯,我們要從我們自己的角色表,權限表中獲取數據,組裝起來,這樣當前的subject就有了這些角色、權限信息 - doGetAuthenticationInfo
此方內實現認證邏輯,根據用戶名從自定義用戶表中檢索出來用戶,然後把用戶名和密碼返回,這裏我們不用自己去對比密碼是否一致,而判斷用戶是否登錄成功,shiro框架會自行判斷,這裏我們還可以設置加密規則的鹽值信息