开发步骤

1.导入相关依赖(一共10个)

2.控制器编写2个方法(注册和登录)

3.自定义认证授权处理器,继承AuthorizingRealm类

4.实现doGetAuthenticationInfo认证方法

5.处理认证方法

5.1.获取用户名
5.2.调用service成判断用户是否存在
5.3.判断用户的状态
5.4.返回一个SimpleAuthenticationInfo认证对象

6.编写shiro配置类(ShiroConfig)

6.1配置ShiroFilterFactoryBean注入SecurityManager
6.2配置SecurityManager注入我们自定义的认证处理器(ShiroRealm)
6.3.配置自定义认证处理器(ShiroRealm)注入自定义密码匹配器(CredentialsMatcher)

7.自定义密码匹配器(继承SimpleCredentialsMatcher类),重写doCredentialsMatch方法

7.1自定义加密解密工具类实现
7.2使用BCryptPasswordEncoder类实现

8.配置application.yml文件

8.1MySQL数据源
8.2通用mapper 的代理类路径

9.异常信息相应处理(可有可无)

10.测试功能,注册和登录

1.pom依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>
    <!--测试启动器-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--springMVC-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--整合Mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>
        <!--mysql数据源-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--通用mapper-->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>
        <!--spring整合shiro-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>

        <!--日志打印-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.6.1</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <!--lombok懒人依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!--JSON转换-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.71</version>
        </dependency>
        <!--加密-->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-crypto</artifactId>
            <version>5.3.3.RELEASE</version>
        </dependency>
    </dependencies>

</project>

2.controller的2个方法:添加和登录

package com.huacheng.controller;

import com.huacheng.domain.User;
import com.huacheng.response.ResponseVO;
import com.huacheng.service.UserService;
import com.huacheng.util.PasswordUtil;
import com.huacheng.util.ResultUtil;
import lombok.extern.log4j.Log4j2;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Log4j2
@RestController
public class LoginController {

    @Autowired
    private UserService userService;

    /**
     * 登录
     *
     * @param username
     * @param password
     * @param rememberMe
     * @return
     */
    @RequestMapping("/login")
    public ResponseVO login(String username, String password, Boolean rememberMe) {
        UsernamePasswordToken token = null;
        try {
            //登录
            token = new UsernamePasswordToken(username, password, false);
            //获取当前的登录对象
            Subject currentUser = SecurityUtils.getSubject();
            currentUser.login(token);
            return ResultUtil.success("登录成功:"+username+"用户欢迎您");
        } catch (Exception e) {
            log.info("登录失败用户名{}", username, e);
            token.clear();
            return ResultUtil.error(e.getMessage());

        }
    }

    @RequestMapping("/add")
    public ResponseVO add(User user) {

        try {
            userService.add(user);
        } catch (Exception e) {
            log.info("新增失败:{}", user);
            return ResultUtil.error("添加失败");

        }
        log.info("新增用户:{}", user);
        return ResultUtil.success("添加成功");
    }
}

3.编写自定义认证授权处理器(ShiroRealm)

package com.huacheng.realms;

import com.huacheng.domain.User;
import com.huacheng.service.UserService;
import com.huacheng.util.PasswordUtil;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import org.apache.shiro.authc.*;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.print.DocFlavor;

@Log4j2
//@Component
public class ShiroRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    /**
     * 授权的方法
     *
     * @param principal
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
        return null;
    }
    /**
     * 认证的方法
     *
     * @param token
     * @return
     */

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {

        //1.获取用户名
        String username = (String) token.getPrincipal();
        User user = userService.findUserByUsername(username);
        //2.判断用户的账号是否存在
        if (user == null) {
            log.info("用户名或者密码错误user:{}", user);
            throw new UnknownAccountException("用户名或者密码错误");
        }

        //3.判断用户的状态是否可用
        if (user.getStatus() == 0) {
            log.info("帐号已被锁定,禁止登录,user:{}", user);
            throw new LockedAccountException("帐号已被锁定,禁止登录!");
        }

        //4.返回一个认证对象
        log.info("登录成功:{}", user.getUsername() + "用户欢迎您");
        return new SimpleAuthenticationInfo(user.getId(),
                user.getPassword(),
                getName());
    }
}

4.编写shiro配置类(ShiroConfig)

package com.huacheng.config;

import com.huacheng.credentials.CredentialsMatcher;
import com.huacheng.realms.ShiroRealm;
import org.apache.shiro.mgt.SecurityManager;
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;

@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
      /*  // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/index.html");*/
        return shiroFilterFactoryBean;
    }

    @Bean
    public SecurityManager securityManager(ShiroRealm myRealms) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //注入我们自定义的认证授权处理器
        securityManager.setRealm(myRealms);
        return securityManager;
    }


    @Bean
    public ShiroRealm shiroRealm(CredentialsMatcher credentialsMatcher) {
        ShiroRealm myRealms = new ShiroRealm();
        //注入自定义的密码匹配器
        myRealms.setCredentialsMatcher(credentialsMatcher);
        return myRealms;
    }


}

5.自定义密码匹配器(这里我用2中方式都可行)

package com.huacheng.credentials;

import com.huacheng.util.PasswordUtil;
import lombok.extern.java.Log;
import lombok.extern.log4j.Log4j2;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;

/**
 * Shiro-密码凭证匹配器(验证密码有效性)
 */
@Log4j2
@Component
public class CredentialsMatcher extends SimpleCredentialsMatcher {


    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        UsernamePasswordToken utoken = (UsernamePasswordToken) token;
        //1.获得用户输入的明文密码
        String loginPassword = new String(utoken.getPassword());
        //2.获得数据路的密文密码
        String dbPassword = (String) info.getCredentials();
        //3.进行密码的比对


        //第一种方式,使用自己的加密解密方法比对密码
      /*  String decryptPassword = null;
        try {
            decryptPassword = PasswordUtil.decrypt(dbPassword, utoken.getUsername());
        } catch (Exception e) {
            log.info("密码解密失败{}", loginPassword);
            throw new RuntimeException("密码解密失败");
        }
        if (!decryptPassword.equals(loginPassword)) {
            throw new IncorrectCredentialsException("用户名或者密码错误");
        }*/

        //第二种方式,使用BCryptPasswordEncoder进行解密
        if (!passwordEncoder.matches(loginPassword, dbPassword)) {
            throw new IncorrectCredentialsException("用户名或者密码错误");
        }
        return true;
    }
}

6.统一异常处理的控制器

package com.huacheng.controller;

import com.huacheng.enums.ResponseStatus;
import com.huacheng.exception.Myexception;
import com.huacheng.response.ResponseVO;
import com.huacheng.util.CommonConst;
import com.huacheng.util.ResultUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.lang.reflect.UndeclaredThrowableException;

/**
 * 统一异常处理类<br>
 * 捕获程序所有异常,针对不同异常,采取不同的处理方式
 *
 * @author yadong.zhang (yadong.zhang0415(a)gmail.com)
 * @version 1.0
 * @website https://www.zhyd.me
 * @date 2018/4/24 14:37
 * @since 1.0
 */
@Slf4j
@ControllerAdvice
public class ExceptionHandleController {

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ResponseVO handle(Throwable e) {


        if (e instanceof Myexception) {
            return ResultUtil.error(e.getMessage());
        }
        if (e instanceof UndeclaredThrowableException) {
            e = ((UndeclaredThrowableException) e).getUndeclaredThrowable();
        }
        ResponseStatus responseStatus = ResponseStatus.getResponseStatus(e.getMessage());
        if (responseStatus != null) {
            log.error(responseStatus.getMessage());
            return ResultUtil.error(responseStatus.getCode(), responseStatus.getMessage());
        }
        e.printStackTrace(); // 打印异常栈
        return ResultUtil.error(CommonConst.DEFAULT_ERROR_CODE, ResponseStatus.ERROR.getMessage());
    }

}

7.使用postman测试

测试添加

image.png

测试登录

image.png
image.png


uyoaix
17 声望0 粉丝

菜鸟一枚