需求:對接第三方登陸,實作繞過原有Shiro認證登陸。
文章目錄
- 一、實作思路
- 1. 現狀分析
- 2. 使用者來源
- 3. 所屬範圍
- 二、實作方案
- 2.1. 自定義登入認證規則
- 2.2. Shiro認證枚舉
- 2.3. 密碼和非密碼登入
- 2.4. 規則配置
- 2.5. 自定義Realm
- 2.6. 案例使用
一、實作思路
1. 現狀分析
系統權架構預設使用Shiro 認證授權機制
2. 使用者來源
從統一認證平台登入跳轉過來的使用者
3. 所屬範圍
二、實作方案
2.1. 自定義登入認證規則
package com.gblfy.config.skipshiro;
import com.gblfy.config.skipshiro.enums.ShiroApproveLoginType;
import org.apache.shiro.authc.UsernamePasswordToken;
/**
* 自定義token 實作免密和密碼登入
* <p>
* 1.賬号密碼登陸(password)
* 2.免密登陸(nopassword)
* </p>
*
* @author gblfy
* @date 2021-10-22
*/
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;
}
}
2.2. Shiro認證枚舉
package com.gblfy.config.skipshiro.enums;
/**
* Shiro認證枚舉
* @author gblfy
* @date 2021-10-22
*/
public enum ShiroApproveLoginType {
/** 密碼登入 */
PASSWORD("PASSWORD"),
/** 密碼登入 */
NOPASSWD("NOPASSWORD");
/** 狀态值 */
private String code;
private ShiroApproveLoginType(String code) {
this.code = code;
}
public String getCode() {
return code;
}
}
2.3. 密碼和非密碼登入
package com.gblfy.config.skipshiro;
import com.gblfy.config.skipshiro.enums.ShiroApproveLoginType;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
/**
* 自定義登入認證方案
* <p>
* 1.免密登入,不加密
* 2.密碼登入,md5加密
* </p>
*
* @author gblfy
* @date 2021-10-22
*/
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);
}
}
2.4. 規則配置
customCredentialsMatch() {
EasyCredentialsMatch customCredentialsMatch = new EasyCredentialsMatch();
customCredentialsMatch.setHashAlgorithmName("md5");
customCredentialsMatch.setHashIterations(3);
customCredentialsMatch.setStoredCredentialsHexEncoded(true);
return customCredentialsMatch;
}
2.5. 自定義Realm
public class UserRealm extends AuthorizingRealm {
/**
* 權限認證
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//權限認證 代碼省略
}
/**
* 登入認證
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
EasyUsernameToken upToken = (EasyUsernameToken) token;
String username = upToken.getUsername();
SysUser user = null;
// 密碼登入
if (upToken.getType().getCode().equals(LoginType.PASSWORD.getCode())) {
String password;
if (upToken.getPassword() != null) {
password = new String(upToken.getPassword());
try {
user = loginService.login(username, password);
}
catch (Exception e) {
log.info("對使用者[" + username + "]進行登入驗證..驗證未通過{}", e.getMessage());
throw new AuthenticationException(e.getMessage(), e);
}
}
} else if (upToken.getType().getCode().equals(LoginType.NOPASSWD.getCode())) {
// 第三方登入 TODO
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, upToken.getPassword(), getName());
return info;
}
}
2.6. 案例使用
(String username, String password, Boolean rememberMe) {
EasyUsernameToken token = new EasyUsernameToken(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);
}
}