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框架会自行判断,这里我们还可以设置加密规则的盐值信息