SpringBoot+Shiro接入LDAP

背景:最近在把公司之前的项目架构升级到SpringBoot,同时因为之前项目需要为每个人到开一个账号有点麻烦,所以这次升级的时候加入了LDAP,让公司的人通过OA账号就能登录,同时保留原有的登录,让没有OA账号的能够走自己的登录

关于LDAP可以去看我写的LDAP的博客,里面简单的介绍了什么是LDAP,Shiro的话可以去网上看看教程,后期可能会写一篇教程。

Shiro的登录流程

shiro的登录流程简单来说有三步:

  • 根据usernam和password生成UsernamePasswordToken
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
  • 使用生成的token进行登录
Subject subject = SecurityUtils.getSubject();//生成subject
subject.login(token);
  • 实现自定义的Realm,重写doGetAuthenticationInfo方法,doGetAuthenticationInfo方法里面写我们自己的登录过程
public class UserRealm extends AuthorizingRealm{
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token){
			//实现自己的登录流程
	}
}

如果只是简单的登录,实现上面三个步骤即可,但是因为我们接入了LDAP的登录,所以我们这里需要对登录类型进行判断,是LDAP的登录走LDAP,不是的走自己的登录。所以我们需要继承UsernamePasswordToken,加入一个变量loginType,来标志登录类型

@Getter
public class CustomToken extends UsernamePasswordToken {

    private Integer loginType;//1为LDAP登录

    public CustomToken(String username, String password, Integer loginType) {
        super(username, password);
        this.loginType = loginType;
    }
}

我们使用CustomToken来生成token,在创建token的时候除了传入username和password还有传入loginType。

CustomTokentoken cToken = new CustomToken(username, password,loginType);

登录还是一样

subject.login(cToken)

在我们实现的doGetAuthenticationInfo方法,需要做一些改变。先把token转为我们自己的CustomTokentoken,然后去除logintype,判断logintype是否是1,是1的话走LDAP,这里因为公司有提供访问的接口,不用搭LDAP服务了

 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        CustomTokentoken cToken= (CustomTokentoken ) token;
        int loginType = cToken.getLoginType();
        String username = (String) cToken.getPrincipal();
        String password = String.valueOf(cToken.getPassword());
        // 走LDAP
        if (loginType == 1){
            log.info("走的LDAP登录: [username: "+ username +"]");
            //下面是跟我们的业务有关,不需要写
            String ssoUser = SsoRestful.authenticateSSOUser(username, password);
            String[] splitSsoUser = ssoUser.split(",");
            String cn = splitSsoUser[splitSsoUser.length - 2];
            String[] cnSplit = cn.split(":");
            String realmName = cnSplit[1];
            String[] splitUser = splitSsoUser[0].substring(1).split(":");
            //上面的可以省略
            password = new SimpleHash("md5",password,ByteSource.Util.bytes(username),2).toHex();
            if (("\"true\"").equals(splitUser[1])){
                return new SimpleAuthenticationInfo(username,password,ByteSource.Util.bytes(username),realmName);
            }else {
                log.error("username[" + username
                        + "] or password error");
                throw new UnknownAccountException("username[" + username
                        + "] error");
            }
        }
        //走自己的用户登录
        User user = userService.findByName(username, null);
        if (user == null) {
            log.error("username[" + username
                    + "] login error, there is no user");
            throw new UnknownAccountException("username[" + username
                    + "] login error, there is no user");
        }
        if ("0".equals(user.getIsOpen())) {
            log.info("the current user[" + username
                    + "] has been closed, can not login.");
            return null;
        }

        // 交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现
        return new SimpleAuthenticationInfo(
                // 用户名
                user.getUserName(),
                // 密码
                user.getPassword(),
                // salt=username+salt
                ByteSource.Util.bytes(user.getCredentialsSalt()),
                // realm name
                user.getRealName()
        );
    }

还有一点需要注意的是,从源码中可知,登录结束后,shiro会进行密码匹配,去校验你输入的密码是否正确。
在这里插入图片描述
Shiro的密码匹配有好几种,有简单匹配的,就是密码明文匹配,也有密码加密后匹配的,这里我们用的是密码加密后匹配。

    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        hashedCredentialsMatcher.setHashIterations(2);
        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
        return hashedCredentialsMatcher;
    }

因此我们在走LDAP登录的时候,当登录成功后,需要手动的把密码,按照上面的规则就行加密再返回,否则会出现密码匹配失败的错误

 password = new SimpleHash("md5",password,ByteSource.Util.bytes(username),2).toHex();//加密算法是MD5,salt是username,加密两次
            if (("\"true\"").equals(splitUser[1])){
                return new SimpleAuthenticationInfo(username,password,ByteSource.Util.bytes(username),realmName);

走自己的登录就不需要改动什么,跟之前的一样即可

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
### 回答1: springboot+shiro+jwt 是一种常见的后端技术组合,其中 springboot 是一个基于 Spring 框架的快速开发框架,shiro 是一个安全框架,用于身份验证、授权和加密等功能,jwt 是一种基于 token 的身份验证机制,可以用于前后端分离的应用中。这种技术组合可以帮助开发者快速搭建安全可靠的后端服务。 ### 回答2: Springboot是一个开源的Java开发框架,是基于Spring框架的远程服务器控制技术方案,是现代化的全栈框架,集成丰富,提供了大量的开箱即用的组件,可以大大简化开发人员的开发工作。 Shiro是一个强大的轻量级安全框架,支持用户身份识别、密码加密、权限控制、会话管理等一系列安全功能,被广泛应用于JavaWeb开发中。 JWT(JSON Web Token)是一种开放标准(RFC 7519),定义了一种简洁的、自包含的方式,用于通信双方之间以JSON对象的形式安全地传递信息。JWT可以用于状态管理和用户身份认证等场景。 在使用SpringBoot开发Web应用过程中,Shiro与JWT可以同时用于用户身份认证和权限控制。Shiro提供了一系列的身份识别、密码加密、权限控制、会话管理等功能,而JWT则可以实现无状态的身份认证。使用Shiro和JWT,可以有效地保护Web应用的安全,避免被恶意攻击者利用。 具体而言,使用Shiro和JWT可以将用户认证的主要逻辑统一在一起,实现更加优雅的认证和授权过程。同时,这样的组合也可以避免一些常见的安全漏洞,比如会话劫持、XSS攻击、CSRF等。 在实际开发中,使用SpringBoot Shiro JWT可以方便地进行二次开发,进一步优化开发成本和提高开发效率。同时,使用这个组合可以让开发者更好地专注于业务逻辑的开发,而无需关注安全问题,从而提高开发质量和开发人员的工作效率。 ### 回答3: Spring Boot是一种基于Spring框架的快速开发微服务的工具,能够使开发者可以快速构建基于Spring的应用程序。而Shiro是一个强大易用的Java安全框架,可用于身份验证、权限控制、加密等。JWT(JSON Web Token)是一种基于JSON的安全令牌,可用于在客户端和服务器之间传递信息。 在使用Spring Boot开发Web应用程序时,通常需要进行用户身份验证和访问控制,这时候就可以使用Shiro来实现这些功能。同时,由于Web应用程序需要跨域访问,因此使用JWT可以方便地实现身份验证和授权的管理。 在使用Spring Boot和Shiro时,可以使用JWT作为身份验证和授权的管理工具。此时,需要进行以下几个步骤: 1.添加Shiro和JWT的依赖 在Spring Boot项目中,可以通过Maven或Gradle等工具添加Shiro和JWT的依赖。例如,可以添加以下依赖: <!-- Shiro依赖 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.7.0</version> </dependency> <!-- JWT依赖 --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> 2.配置Shiro 在Spring Boot项目中,可以通过在application.properties或application.yml文件中进行Shiro的配置。例如,可以配置以下内容: # Shiro配置 shiro: user: loginUrl: /login # 登录页面URL jwt: secret: my_secret # JWT加密密钥 expiration: 1800000 # JWT过期时间,单位为毫秒,默认30分钟 3.创建Shiro的Realm 在Shiro中,Realm是用于从应用程序中获取安全数据(如用户、角色和权限)的组件。因此,需要创建Shiro的Realm,用于管理用户的认证和授权。 例如,可以创建一个自定义的Realm,其中包括从数据库中获取用户和角色的方法: public class MyRealm extends AuthorizingRealm { @Autowired private UserService userService; /** * 认证,验证用户身份 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = (String) token.getPrincipal(); User user = userService.findByUsername(username); if (user == null) { throw new UnknownAccountException("用户名或密码错误"); } String password = user.getPassword(); return new SimpleAuthenticationInfo(user.getUsername(), password, getName()); } /** * 授权,验证用户的访问权限 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = (String) principals.getPrimaryPrincipal(); User user = userService.findByUsername(username); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); Set<String> roles = user.getRoles(); authorizationInfo.setRoles(roles); Set<String> permissions = user.getPermissions(); authorizationInfo.setStringPermissions(permissions); return authorizationInfo; } } 4.使用JWT进行身份验证和授权管理 在Spring Boot应用程序中,使用Shiro和JWT来进行身份验证和授权管理的流程大致如下: 4.1 前端用户进行登录操作,将用户名和密码发送到后台服务。 4.2 后台服务进行身份验证,将用户身份信息生成JWT并返回给前端。 4.3 前端保存JWT,并在后续的请求中将其发送到后台服务。 4.4 后台服务验证JWT的有效性,并根据用户的角色和权限信息进行访问控制。 综上所述,Spring Boot、Shiro和JWT可以很好地配合使用,实现Web应用程序的身份验证和授权管理。这种组合方案可以提高开发效率和系统安全性,同时也适用于微服务架构中对身份验证和授权的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lpepsi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值