1. 自定义登录类型枚举
package com.smartsite.framework.shiro.enums;
/**
* @ClassName LoginType
* @Description Shiro认证枚举
* @Author wangyj
* @Date 22/5/12
*/
public enum LoginType {
/** 密码登录 */
PASSWORD("PASSWORD"),
/** 密码登录 */
NOPASSWD("NOPASSWORD");
/** 状态值 */
private String code;
private LoginType(String code) {
this.code = code;
}
public String getCode() {
return code;
}
}
2. 自定义登录认证规则
package com.smartsite.framework.shiro.token;
import com.smartsite.framework.shiro.enums.LoginType;
import org.apache.shiro.authc.UsernamePasswordToken;
/**
* @author wangyj
* @className CustomToken
* @description
* @date 22/5/12
*/
public class CustomToken extends UsernamePasswordToken {
private static final long serialVersionUID = -2564928913725078138L;
private LoginType type;
public CustomToken() {
super();
}
/**
* 免密登录
*/
public CustomToken(String username) {
super(username, "", false, null);
this.type = LoginType.NOPASSWD;
}
/**
* 账号密码登录
*/
public CustomToken(String username, String password, boolean rememberMe) {
super(username, password, rememberMe, null);
this.type = LoginType.PASSWORD;
}
public LoginType getType() {
return type;
}
public void setType(LoginType type) {
this.type = type;
}
}
3. 修改自定义Realm
public class UserRealm extends AuthorizingRealm {
...
/**
* 登录认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
CustomToken upToken = (CustomToken) token;
String username = upToken.getUsername();
String password = "";
SysUser user = null;
// 通过登录类型进行免密登录或者正常登录
if (upToken.getType().getCode().equals(LoginType.PASSWORD.getCode())) {
if (upToken.getPassword() != null) {
password = new String(upToken.getPassword());
}
try {
user = loginService.login(username, password);
} catch (CaptchaException e) {
throw new AuthenticationException(e.getMessage(), e);
} catch (UserNotExistsException e) {
throw new UnknownAccountException(e.getMessage(), e);
} catch (UserPasswordNotMatchException e) {
throw new IncorrectCredentialsException(e.getMessage(), e);
} catch (UserPasswordRetryLimitExceedException e) {
throw new ExcessiveAttemptsException(e.getMessage(), e);
} catch (UserBlockedException e) {
throw new LockedAccountException(e.getMessage(), e);
} catch (RoleBlockedException e) {
throw new LockedAccountException(e.getMessage(), e);
} catch (Exception e) {
log.info("对用户[" + username + "]进行登录验证..验证未通过{}", e.getMessage());
throw new AuthenticationException(e.getMessage(), e);
}
}else if (upToken.getType().getCode().equals(LoginType.NOPASSWD.getCode())) {
// 第三方登录 TODO
user = loginService.login(username);
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
return info;
}
...
}
4. loginService补充方法
package com.smartsite.framework.shiro.service;
/**
* 登录校验方法
*/
@Component
public class SysLoginService{
...
public SysUser login(String username) {
// 查询用户信息
SysUser user = userService.selectUserByLoginName(username);
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
recordLoginInfo(user);
return user;
}
...
}
5. 修改下原本登录方法使用的UsernamePasswordToken 改为刚才我们继承重写的CustomToken这样会避免出现通过原方法登录导致的类型转换失败
package com.smartsite.web.controller.system;
/**
* 登录验证
*/
@Controller
public class SysLoginController extends BaseController{
...
@PostMapping("/login")
@ResponseBody
public AjaxResult ajaxLogin(String username, String password, Boolean rememberMe) throws Exception{
password = AesEncryptUtils.decrypt(password);
// 调整为重写的token
CustomToken token = new CustomToken(username, password, rememberMe);
Subject subject = SecurityUtils.getSubject();
try
{
subject.login(token);
return success();
}
catch (AuthenticationException e)
{
String msg = "用户或密码错误";
if (StringUtils.isNotEmpty(e.getMessage()))
{
msg = e.getMessage();
}
return error(msg);
}
}
...
}
6. 最后在免密登录的入口控制是否免密就好
PostMapping("/oss")
public String ossLogin(String username,ModelMap map) throws Exception {
try {
// ... 一些校验
CustomToken token = new CustomToken(username);
Subject subject = SecurityUtils.getSubject();
subject.login(token);
System.out.println("单点登录成功: " + dt);
return "redirect:/index_screen";
}
} catch (AuthenticationException e) {
e.printStackTrace();
}
return "error/business";
}
7. 有在realm自定义密码校验规则的, 需要重写下matcher
public class CustomCredentialsMatch extends HashedCredentialsMatcher {
@Override
public boolean doCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo info) {
CustomToken tk = (CustomToken) authcToken;
if(tk.getType().equals(LoginType.NOPASSWD)){
return true;
}
boolean matches = super.doCredentialsMatch(authcToken, info);
return matches;
}
}
8. shiroConfig里换个匹配器
/**
* 自定义Realm 处理登录 权限
*/
public class UserRealm extends AuthorizingRealm {
...
/**
* 方法名:
* 功能:凭证匹配器
* 描述:指定shiro加密方式和次数
*/
@Bean(name = "customCredentialsMatch")
public CustomCredentialsMatch hashedCredentialsMatch(){
CustomCredentialsMatch hashedCredentialsMatch = new CustomCredentialsMatch();
hashedCredentialsMatch.setHashAlgorithmName("MD5");
hashedCredentialsMatch.setHashIterations(1024);
return hashedCredentialsMatch;
}
...
}
7,8两个步骤我项目不需要, 所以我没试, 需要的朋友可以自己尝试下
有问题欢迎大佬们指正~