开发步骤

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@RestControllerpublic 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//@Componentpublic 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;@Configurationpublic 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@Componentpublic 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@ControllerAdvicepublic 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());    }}