1、自定义登录认证规则
import org.apache.shiro.authc.UsernamePasswordToken;
public class EasyUsernameToken extends UsernamePasswordToken {
private static final long serialVersionUID = -2564928913725078138L;
private ShiroApproveLoginType type;
public EasyUsernameToken() {
super();
}
/**
* 免密登录
*/
public EasyUsernameToken(String username) {
super(username, "", false, null);
this.type = ShiroApproveLoginType.NOPASSWD;
}
/**
* 账号密码登录
*/
public EasyUsernameToken(String username, String password, boolean rememberMe) {
super(username, password, rememberMe, null);
this.type = ShiroApproveLoginType.PASSWORD;
}
public ShiroApproveLoginType getType() {
return type;
}
public void setType(ShiroApproveLoginType type) {
this.type = type;
}
}
枚举类
public enum ShiroApproveLoginType {
/** 密码登录 */
PASSWORD("PASSWORD"),
/** 密码登录 */
NOPASSWD("NOPASSWORD");
/** 状态值 */
private String code;
private ShiroApproveLoginType(String code) {
this.code = code;
}
public String getCode() {
return code;
}
}
2、自定义登录认证方案
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
/**
* 自定义登录认证方案
* 1.免密登录,不加密
* 2.密码登录,SHA256加密
*
*/
public class EasyCredentialsMatch extends HashedCredentialsMatcher {
/**
* 重写方法
* 区分 密码和非密码登录
* 此次无需记录登录次数 详情看SysPasswordService
*/
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
EasyUsernameToken easyUsernameToken = (EasyUsernameToken) token;
//免密登录,不验证密码
if (ShiroApproveLoginType.NOPASSWD.equals(easyUsernameToken.getType())) {
return true;
}
//密码登录
Object tokenHashedCredentials = hashProvidedCredentials(token, info);
Object accountCredentials = getCredentials(info);
return equals(tokenHashedCredentials, accountCredentials);
}
}
3、shiro配置类设置加密规则
/**
* 凭证匹配器
* 将密码校验交给Shiro的SimpleAuthenticationInfo进行处理,在这里做匹配配置
*
* @Author
* @CreateTime 2021/5/06 8:42
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
// HashedCredentialsMatcher shaCredentialsMatcher = new HashedCredentialsMatcher();
EasyCredentialsMatch shaCredentialsMatcher = new EasyCredentialsMatch();
// 散列算法:这里使用SHA256算法;
shaCredentialsMatcher.setHashAlgorithmName(SHA256Util.HASH_ALGORITHM_NAME);
// 散列的次数,比如散列两次,相当于 md5(md5(""));
shaCredentialsMatcher.setHashIterations(SHA256Util.HASH_ITERATIONS);
return shaCredentialsMatcher;
}
4、登录认证
import org.apache.shiro.authc.*;
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;
/**
* @Description Shiro权限匹配和账号密码匹配
*/
public class ShiroRealm extends AuthorizingRealm {
@Resource
private UserService userService;
/**
* 身份认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
EasyUsernameToken easyUsernameToken = (EasyUsernameToken) authenticationToken;
//获取用户的输入的账号.
String username = (String) authenticationToken.getPrincipal();
//通过username从数据库中查找 User对象,如果找到进行验证
//实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
SysUserEntity user = userService.getUserByName(username);
//判断账号是否存在
if (user == null) {
throw new AuthenticationException();
}
//判断账号是否被冻结
if (user.getState() == null || user.getState().equals("PROHIBIT")) {
throw new LockedAccountException();
}
SimpleAuthenticationInfo authenticationInfo;
if(easyUsernameToken.getType().equals(ShiroApproveLoginType.PASSWORD)){
//进行用户名密码验证
authenticationInfo = new SimpleAuthenticationInfo(
user, //用户名
user.getPassword(), //密码
ByteSource.Util.bytes(user.getSalt()), //设置盐值
getName()
);
}else{
//免密验证
authenticationInfo = new SimpleAuthenticationInfo(
user, //用户名
"", //密码
getName()
);
}
return authenticationInfo;
}
}
5、登录方法
public Result login(@RequestBody Map<String,Object> userMap) {
Map<String, Object> map = new HashMap<>();
//进行身份验证
String name = userMap.get("name").toString();
try {
//验证身份和登陆
Subject subject = SecurityUtils.getSubject();
EasyUsernameToken token = new EasyUsernameToken(name);
//进行登录操作
subject.login(token);
return ResultUtil.success();
} catch (IncorrectCredentialsException e) {
return ResultUtil.error(500,"用户不存在或者密码错误");
} catch (LockedAccountException e) {
return ResultUtil.error(500,"登录失败,该用户已被冻结");
} catch (AuthenticationException e) {
return ResultUtil.error(500,"该用户不存在");
}
}