Shiro的使用之认证拦截

    Shiro是一个安全开发框架,它把系统的安全认证等相关功能抽取出来,降低了系统的开发成本。
    
    


一 Shiro实现认证拦截

    步骤: 1 系统调用subject的login方法将用户信息传递给securityManager
          2 securityManager将认证操作委托给Authenticator
          3 Authenticator将用户输入的身份信息发送给Realm
          4 Realm访问数据库获取用户信息并将信息封装并返回
          5 Authenticator对封装的信息进行身份认证
          

image.png
输入用户信息后登陆到系统界面


1.需要的依赖
<dependency>
     <groupId>org.apache.shiro</groupId>
     <artifactId>shiro-spring</artifactId>
     <version>1.5.3</version>
</dependency>
2. Shiro的核心配置对象

在springboot中没有为我们自动配置shiro,所以要手动配置

  • 首先创建一个配置类:SpringShiroConfig类;
  • 然后在配置类中添加SecurityManager接口对象;
  • 在配置类中添加一个ShiroFilterFactoryBean对象;通过此对象实现对匿名访问和认证访问
  • 代码如下:
package com.py.pj.common.config;

import java.util.LinkedHashMap;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author WL
 * @version 创建时间:2020-9-19 13:24:57
 * @Description Shiro的核心配置对象
 * @Configuration 此注解描述的类是一个配置对象,此对象会交给spring处理
 * @Bean 此注解描述的类会被交给spring处理,由spring为我们创建对象
 */
@Configuration
public class SpringShiroConfig {

    
    @Bean
    public SecurityManager securityManager(Realm realm) {
        DefaultWebSecurityManager dsm = new DefaultWebSecurityManager();
        dsm.setRealm(realm);
        return dsm;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean sffBean = new ShiroFilterFactoryBean();
        sffBean.setSecurityManager(securityManager);
          //  设置登录界面url
        sffBean.setLoginUrl("/doLogin");
        
        LinkedHashMap<String, String> map = new LinkedHashMap<>();

        map.put("/bower_components/**", "anon");
        map.put("/modules/**", "anon");
        map.put("/dist/**", "anon");
        map.put("/plugins/**", "anon");

        // 用户登录界面允许匿名访问
        map.put("/user/doLogin", "anon");
        //  退出登陆
        map.put("/doLogout", "logout");
        
        // 除了静态资源,其他的都要认证
        map.put("/**", "authc");

        sffBean.setFilterChainDefinitionMap(map);
        return sffBean;
    }
}
3.业务模块实现
    本模块的业务在realm模块中实现
  • 3.1 根据用户名搜索用户信息

在SysUserMapper中创建findUserByUsername(String username)方法

SysUser findUserByUsername(String username);


mapper映射文件中
<select id="findUserByUsername" resultType="com.py.pj.sys.entity.SysUser">
    select * from sys_users where username=#{username}
</select>
  • 3.2 创建realm业务层
package com.py.pj.sys.realm;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.py.pj.sys.dao.SysUserMapper;
import com.py.pj.sys.entity.SysUser;

/**
 * @author WL
 * @version 创建时间:2020-9-19 14:15:12
 * @Description 授权realm继承认证,所以包含认证和授权功能
 */
@Service
public class ShiroUserRealm extends AuthorizingRealm {

    @Autowired
    private SysUserMapper sysUserMapper;

    /**
     * 设置凭证匹配器匹配规则
     */

    @Override
    public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
        // 创建凭证匹配器对象
        HashedCredentialsMatcher hcm = new HashedCredentialsMatcher();
        // 设置加密算法,与用户密码加密算法保持一直
        hcm.setHashAlgorithmName("MD5");
        // 设置加密次数
        hcm.setHashIterations(1);
        super.setCredentialsMatcher(hcm);
    }

    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // TODO Auto-generated method stub
        return null;
    }

    /**
     * 重写认证 token 是从客户端传来的用户的账号信息
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // 1.获取用户输入的用户名
        UsernamePasswordToken UToken = (UsernamePasswordToken) token;
        String username = UToken.getUsername();
        // 2.基于用户名查用户信息
        SysUser user = sysUserMapper.findUserByUsername(username);
        // 3.判断用户是否存在、是否禁用
        if (user == null) {
            throw new UnknownAccountException();
        }
        if (user.getValid() == 0) {
            throw new LockedAccountException();
        }
        // 4.封装用户信息
        // 盐值是ByteSource格式的所以要转换
        ByteSource credentialsSalt = ByteSource.Util.bytes(user.getSalt());

        System.out.println(user.getPassword());
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, // principal (身份)
                user.getPassword(), // hashedCredentials
                credentialsSalt, // credentialsSalt
                getName());// realName

        return info;
    }

}

  • 3.3 controller层
    
    @RequestMapping("doLogin")
    public JsonResult doLogin(String username,String password) {
        //    每个用户都是一个subject对象
        Subject subject = SecurityUtils.getSubject();
        //    对用户进行封装
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
        //    token被传给securityManager;securityManager在传递给Authentication;Authentication再传给realm,从数据库中获取并封装用户信息
        subject.login(token);
        return new JsonResult("OK");
    }

至此,借助Shiro完成了用户的登陆认证功能。


流浪成疯
7 声望3 粉丝

学习