Shiro用户认证

通过鸟哥文章学习Shiro知识,原文连接:https://mrbird.cc/Spring-Boot-shiro%20Authentication.html

1. 搭建一个Spring Boot Web,然后引入Shiro

  本篇不讲解Spring Boot Web项目搭建,直接在一个Spring Boot Web 项目基础上引入Shiro并做用户认证配置。

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

2. 定义一个Shiro配置类

    定义filterChain配置不配拦截的url

    配置退出过滤器,具体代码实现Shiro已有

    除配置了不拦截的url以外其他url都必须通过认证才能进行访问

@Configuration
public class ShiroConfig {
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 设置securityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 登录的url
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 登录成功后跳转的url
        shiroFilterFactoryBean.setSuccessUrl("/index");
        // 未授权url
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");

        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();

        // 定义filterChain,静态资源不拦截
        filterChainDefinitionMap.put("/febs/**", "anon");
        filterChainDefinitionMap.put("/layui/**", "anon");
        // druid数据源监控页面不拦截
        filterChainDefinitionMap.put("/druid/**", "anon");
        // 配置退出过滤器,其中具体的退出代码Shiro已经替我们实现了
        filterChainDefinitionMap.put("/logout", "logout");
        filterChainDefinitionMap.put("/", "anon");
        // 除上以外所有url都必须认证通过才可以访问,未通过认证自动访问LoginUrl
        filterChainDefinitionMap.put("/**", "authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    @Bean
    public DefaultWebSecurityManager securityManager(){
        // 配置SecurityManager,并注入shiroRealm
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        securityManager.setRealm(shiroRealm());
        return securityManager;
    }

    @Bean
    public ShiroRealm shiroRealm(){
        // 配置Realm,需自己实现
        ShiroRealm shiroRealm = new ShiroRealm();
        return shiroRealm;
    }
}

3. 配置完ShiroConfig后,接下来对Realm进行实现,然后注入到SecurityManager中。

doGetAuthorizationInfo:获取用户角色和权限(本篇只讲解验证)
doGetAuthenticationInfo:对登录的账号密码进行验证
public class ShiroRealm extends AuthorizingRealm {
    @Autowired
    private BaseUserService baseUserService;

    /**
     * 获取用户角色和权限
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
        return null;
    }

    /**
     * 登录认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        // 获取用户输入的用户名和密码
        String userName = (String) token.getPrincipal();
        String password = new String((char[]) token.getCredentials());

        System.out.println("用户" + userName + "认证-----ShiroRealm.doGetAuthenticationInfo");

        // 通过用户名到数据库查询用户信息
        BaseUser user = baseUserService.findByName(userName);

        if (user == null) {
            throw new UnknownAccountException("用户名或密码错误!");
        }
        if (!password.equals(user.getPassword())) {
            throw new IncorrectCredentialsException("用户名或密码错误!");
        }
        /*if (user.getStatus().equals("0")) {
            throw new LockedAccountException("账号已被锁定,请联系管理员!");
        }*/
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
        return info;
    }
}

4. 密码存储通过MD5加密处理

    这里用的是一般加盐处理,普通的用户名+密码再MD5

public class Md5Util {

    private static final String ALGORITHM_NAME = "md5";

    private static final int HASH_ITERATIONS = 5;

    public static String encrypt(String username, String password) {
        String source = StringUtils.lowerCase(username);
        password = StringUtils.lowerCase(password);
        return new SimpleHash(ALGORITHM_NAME, password, ByteSource.Util.bytes(source), HASH_ITERATIONS).toHex();
    }
}

5.Controller

  获取到用户输入的用户名和密码后,对其进行验证

UsernamePasswordToken 是用来存储用户名和密码
@PostMapping("/login")
    public Response login(String username, String password){
        //密码MD5加密
        password = Md5Util.encrypt(username, password);
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        //获取Subject对象
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(token);
            return new Response().success();
        } catch (AuthenticationException e) {
            return new Response().error().data("认证失败!");
        } catch (Exception e){
            return new Response().error().data(e.getMessage());
        }
    }

 

Guess you like

Origin blog.csdn.net/Caozefei_2018/article/details/109848856