springboot集成shiro实现用户登录认证

Apache Shiro 是一个功能强大且易于使用的Java安全框架,可执行身份验证、授权、加密和会话管理。使用Shiro易于理解的API,您可以快速轻松地保护任何应用程序-从最小的移动应用程序到最大的web和企业应用程序。

下面即springboot集成shiro,实现用户登录认证功能

1.原理

shiro外部架构如下:

主要包括三大实体:Subject、Realm、和SecurityManager。

Subject即当前用户,我们可以通过Subject自带的 SecurityUtils.getSubject()方法获取当前对象,并通过当前用户拿到shiro的session,进行后续的认证授权等。

SecurityManager即安全管理器,可以视为拦截器,拦截请求,并转至shiro中处理。

Realm,可以有1个或多个Realm,即安全实体数据源,即用于获取安全实体的;可以是JDBC实现,也可以是LDAP实现,或者内存实现等等;一般由用户自定义实现。

 

shiro实现过程一般如下,编写shiro配置文件,配置对应的加密方式,并注册进Realm中,然后把对应的realm注入shiro配置中进行注册;编写Realm类,实现对应的登录认证、授权等功能。

2.注入依赖

<!--shiro-->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.0</version>
</dependency>

3.编写shiro配置文件

@Configuration
public class ShiroConfig {

    //此处用于实现授权功能,配置需要拦截的接口
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        //拦截页面
        Map<String, String> filterMap = new LinkedHashMap<>();
        //登录/登出,所有人的权限
        filterMap.put("/user/login", "anon");
        filterMap.put("/user/logout", "anon");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        //未登录页面跳转
        shiroFilterFactoryBean.setLoginUrl("/user/show");
        //未有权限页面跳转
        shiroFilterFactoryBean.setUnauthorizedUrl("/user/unauthorized");

        return shiroFilterFactoryBean;
    }
    
    //注入对应的userRealm类
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager SecurityManager = new DefaultWebSecurityManager();
        SecurityManager.setRealm(userRealm);
        return SecurityManager;
    }
    @Bean
    public UserRealm userRealm() {
        UserRealm userRealm = new UserRealm();
        //注册MD5加密
        userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return userRealm;
    }

    /**
     * 设置shiro加密方式
     *
     * @return HashedCredentialsMatcher
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        // 使用md5 算法进行加密
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        // 设置散列次数: 意为加密几次
        hashedCredentialsMatcher.setHashIterations(2);

        return hashedCredentialsMatcher;
    }

}

4.编写userRealm类,实现登录拦截

@Slf4j
public class UserRealm extends AuthorizingRealm {
    @Autowired
    private UserManageService userManageService;

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        /**配置权限
        *此处User实体需配置属性roles,用户权限
        *获取当前用户对象
         * */
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        Subject subject= SecurityUtils.getSubject();
        UserAccount currentUser =(UserAccount) subject.getPrincipal();
        authorizationInfo.addStringPermission(currentUser.getRoles());
        log.info("用户权限为:"+currentUser.getRoles());
        return authorizationInfo;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        //用户名/密码认证
        //从接口处获取得到的用户名
        String username = token.getUsername();

        //调用mybatis_plus中的方法,查询数据库中用户名对应的数据
        QueryWrapper<UserAccount> wrapper = new QueryWrapper<>();
        wrapper.eq("Username",username);
        UserAccount user=userManageService.getOne(wrapper);

        //为空,即用户名不存在
        if(user==null){
            return null;
        }else {
            log.info(user.getUsername());
        }

        //principal:认证的实体信息,可以是username,也可以是数据库表对应的用户的实体对象
        Object principal = user.getUsername();
        return  new SimpleAuthenticationInfo(user, user.getPassword() , ByteSource.Util.bytes(principal),getName());
    }
}

注意:此处进行登录验证时使用了MD5加密,即数据库中存储的密码应是MD5加密后的密文密码,而不是明文密码。

示例如下:

//md5加密
admin.setPassword(new Md5Hash(admin.getPassword(), admin.getUsername(),2).toString());

5.编写controller接口

//用户登录(使用用户名)
    @PostMapping("/login")
    public CommonResult<Object> UserLogin(@RequestBody UserAccount user)
    {
        String username=user.getUsername();
        String password=user.getPassword();

        //shiro验证
        Subject subject= SecurityUtils.getSubject();
        //根据用户名密码生成一个令牌
        UsernamePasswordToken token=new UsernamePasswordToken(username,password);
        try {
            subject.login(token);    //执行登录操作
        } catch (UnknownAccountException e) {
            log.info("登录用户不存在");
            return new CommonResult<>(416,"用户不存在",username);
        } catch (IncorrectCredentialsException e) {
            log.info("登录密码错误");
            return new CommonResult<>(412,"密码错误,请重新登录",password);
        }catch (AuthenticationException e) {
            log.warn("用户登录异常:" + e.getMessage());
            return new CommonResult<>(416,"账户异常",username);
        }

        return new CommonResult<>(200,"登录成功",username);

    }

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>