(五)Spring Boot 集成 Shiro 多登陸方式登錄

github

歷史文章

(一)Spring Boot 集成 Shiro 權(quán)限管理與密碼加鹽

(二)Spring Boot 集成 Shiro 記住我功能

(三)Spring Boot 集成 Shiro 權(quán)限緩存功能

(四)Spring Boot 集成 Shiro 用戶管理與登錄保護(hù)

主要完成功能

用戶可以使用賬號(hào)密碼登錄或者手機(jī)驗(yàn)證碼登錄

shiro 有三種認(rèn)證策略 AuthenticationStrategy

默認(rèn)是 AtLeastOneSuccessfulStrategy

修改 MyRealm 為 BaseRealm 并將 doGetAuthenticationInfo 交由子類實(shí)現(xiàn)

實(shí)現(xiàn)兩個(gè) Realm

  • PasswordRealm
  • PhoneCodeRealm
public class PasswordRealm extends BaseRealm {

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //獲取用戶的輸入的賬號(hào)
        UserToken userToken = (UserToken) authenticationToken;
        if (userToken.getLoginType() == LoginType.PASSWORD) {
            //通過(guò)username從數(shù)據(jù)庫(kù)中查找 User對(duì)象
            User user = userMapper.selectByName(userToken.getUsername());
            if (user == null) {
                //沒(méi)有返回登錄用戶名對(duì)應(yīng)的SimpleAuthenticationInfo對(duì)象時(shí),就會(huì)在LoginController中拋出UnknownAccountException異常
                throw new UnknownAccountException("用戶不存在");
            }
            //使用密碼加鹽的方式驗(yàn)證密碼的安全,鹽為用戶注冊(cè)時(shí)設(shè)置的用戶名
            SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                    user, //用戶名
                    user.getPassword(), //密碼
                    ByteSource.Util.bytes(user.getSalt()),//salt
                    getName()  //realm name
            );
            return authenticationInfo;
        } else {
            return null;
        }
    }
}
public class PhoneCodeRealm extends BaseRealm {
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UserToken userToken = (UserToken) authenticationToken;
        if (userToken.getLoginType() == LoginType.PHONE_CODE) {
            User user = userMapper.selectByName(userToken.getUsername());
            if (user == null) {
                throw new UnknownAccountException("用戶不存在");
            }
            SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                    user, //用戶名
                    "1234", //驗(yàn)證碼,該驗(yàn)證碼應(yīng)該從數(shù)據(jù)庫(kù)中查找
                    getName()  //realm name
            );
            return authenticationInfo;
        } else {
            return null;
        }
    }
}
public enum LoginType {
    PASSWORD, PHONE_CODE;
}
public class UserToken extends UsernamePasswordToken {
    private LoginType loginType;

    public UserToken(String username, String password, boolean rememberMe, LoginType loginType) {
        super(username, password, rememberMe);
        this.loginType = loginType;
    }

    public LoginType getLoginType() {
        return loginType;
    }

    public void setLoginType(LoginType loginType) {
        this.loginType = loginType;
    }
}

修改 ShiroConfig 配置類

由之前的配置的單個(gè) Realm 改為 Realm List

@Bean
SecurityManager securityManager() {
    DefaultSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
    // >>>>修改為 List
    List<Realm> realmList = new ArrayList<>();
    realmList.add(passwordRealm());
    realmList.add(phoneRealm());
    defaultSecurityManager.setRealms(realmList);
    // <<<<
    defaultSecurityManager.setRememberMeManager(rememberMeManager());
    defaultSecurityManager.setCacheManager(cacheManager());
    defaultSecurityManager.setSessionManager(sessionManager());
    return defaultSecurityManager;
}

@Bean
BaseRealm passwordRealm() {
    BaseRealm myRealm = new PasswordRealm();
    myRealm.setCredentialsMatcher(hashedCredentialsMatcher()); //設(shè)置解密規(guī)則
    return myRealm;
}

@Bean
BaseRealm phoneRealm() {
    return new PhoneCodeRealm();//去除解密策略
}

修改登錄接口

/**
 * 登錄接口
 *
 * @param username
 * @param password
 */
@GetMapping("/doLogin")
public String doLogin(String username, String password, boolean rememberMe) {
    Subject subject = SecurityUtils.getSubject();
    if (!subject.isAuthenticated()) {
        try {
            UserToken token = new UserToken(username, password, rememberMe, LoginType.PASSWORD);
            subject.login(token);
            return "登錄成功";
        } catch (AuthenticationException e) {
            e.printStackTrace();
            return "登錄失敗";
        }
    } else {
        return "已經(jīng)登錄成功";
    }
}

/**
 * 登錄接口 使用 code 替換 password,并去掉加解密
 *
 * @param username
 * @param code
 */
@GetMapping("/doLoginByCode")
public String doLoginByCode(String username, String code, boolean rememberMe) {
    Subject subject = SecurityUtils.getSubject();
    if (!subject.isAuthenticated()) {
        try {
            UserToken token = new UserToken(username, code, rememberMe, LoginType.PHONE_CODE);
            subject.login(token);
            return "登錄成功";
        } catch (AuthenticationException e) {
            e.printStackTrace();
            return "登錄失敗";
        }
    } else {
        return "已經(jīng)登錄成功";
    }
}

測(cè)試

使用賬號(hào)密碼登錄,之后退出

使用賬號(hào)驗(yàn)證碼登錄,之后退出

有用的話關(guān)注我的微信公眾號(hào)吧!
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容