Shiro 实现免密登陆

需求:对接第三方登陆,实现绕过原有Shiro认证登陆。

文章目录

一、实现思路
1. 现状分析

系统权框架默认使用Shiro 认证授权机制

2. 用户来源

从统一认证平台登录跳转过来的用户

3. 所属范围

登录限制由统一认证平台去做,但是,跳转过来的用户仍然走您本系统的登录流程,只是走本系统的登录流程时,想跳过Shiro 对用户密码的校验,校验所属范围为Shiro 认证机制,其他功能照旧;

二、实现方案
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. 规则配置
    @Bean
    public EasyCredentialsMatch 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. 案例使用
    public AjaxResult login(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);
        }
    }
在 Spring Boot 中使用 Shiro 实现免密登录的步骤如下: 1. 导入 Shiro 和 Spring Boot 的相关依赖。在 pom.xml 文件中添加以下依赖: ```xml <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.7.1</version> </dependency> ``` 2. 创建一个自定义的 ShiroRealm 类,并继承 org.apache.shiro.realm.AuthenticatingRealm 类。在该类中重写 doGetAuthenticationInfo 方法,用于验证用户身份信息。这里可以通过用户名和密码进行验证,也可以通过其他方式实现免密登录。 3. 在 application.properties 或 application.yml 文件中配置 Shiro 的相关属性。例如,配置 Shiro 使用的 Realm 类和登录 URL: ```yaml shiro: authc: loginUrl: /login realms: myRealm: authenticationTokenClass: org.apache.shiro.authc.UsernamePasswordToken ``` 4. 在 Spring Boot 的入口类上添加 @EnableShiro 注解,启用 Shiro 功能。 5. 创建一个登录接口,处理用户登录请求。在该接口中,可以使用 Shiro 的 Subject 类来进行登录验证。例如: ```java @PostMapping("/login") public String login(String username, String password) { Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, password); try { subject.login(token); return "登录成功"; } catch (AuthenticationException e) { return "用户名或密码错误"; } } ``` 这样,当用户访问登录接口并提供正确的用户名和密码时,就可以实现免密登录,并返回登录成功的提示信息。当用户提供错误的用户名或密码时,将返回错误提示信息。 注意:以上只是简单示例,实际应用中可能需要更复杂的逻辑和安全措施。建议参考 Shiro 的官方文档和示例代码来进行具体的实现和配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值