SpringBoot 整合 Shiro (一)用户认证

SpringBoot 整合 Shiro 进行用户认证主要是通过以下三点:
(1)定义一个ShiroConfig,配置SecuityManager,其中SecurityManagershiro的管理器,管理着所有的Subject
(2) 在 ShiroConfig 配置 Shiro 的过滤工厂类 ShiroFilterFactoryBean,用于过滤一些不需要的资源,如静态资源;其依赖于 SecurityManager;
(3) 自定义认证过程 Realm 的实现,Realm 包含授权 doGetAuthorizationInfo() 和 认证 doGetAuthenticationInfo()

ok,开始实现,技术选型:springboot + h2数据库 + shiro + mybatis-plus
1、先引入依赖:

		<!--thymeleaf-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- shiro-spring -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.2.0</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--h2-->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1.tmp</version>
        </dependency>

2、建立数据库:在 resources 目录下新建一个包db,导入schema-h2.sqldata-h2.sql这两个文件,
schema-h2.sql

DROP TABLE IF EXISTS user;

CREATE TABLE user
(
	id BIGINT(20) NOT NULL COMMENT '主键ID',
	username VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
	password VARCHAR(128) NULL DEFAULT NULL COMMENT '密码',
	create_time DATE NULL DEFAULT NULL COMMENT '创建时间',
	status CHAR(2) NULL DEFAULT NULL COMMENT '状态',
    PRIMARY KEY (id)
);

data-h2.sql

DELETE FROM user;

INSERT INTO user (id, username, password, create_time, status) VALUES
(1, 'Jone', 'e10adc3949ba59abbe56e057f20f883e', null, '1'),
(2, 'Jack', 'e10adc3949ba59abbe56e057f20f883e', null, '1'),
(3, 'Tom', 'e10adc3949ba59abbe56e057f20f883e', null, '1'),
(4, 'Sandy', 'e10adc3949ba59abbe56e057f20f883e', null, '0'),
(5, 'Billie', 'e10adc3949ba59abbe56e057f20f883e', null, '0');

3、建立和数据库对应的实体类:

@Data
public class User implements Serializable {

    private Long   id;
    @TableField("username")
    private String userName;
    @TableField("password")
    private String password;
    @TableField("create_time")
    private Date   createTime;
    @TableField("status")
    private String status;
}

4、建立 dao层 和 service层

dao层:

public interface UserMapper extends BaseMapper<User> {
}
service层:
接口:

public interface UserService extends IService<User> {

    User findUserByUserName(String userName);
}
--------------------------------------------------------------
实现类:

@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Override
    public User findUserById(Long id) {
        return baseMapper.selectById(id);
    }

    @Override
    public User findUserByUserName(String userName) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.eq(User::getUserName, userName);
        return baseMapper.selectOne(queryWrapper);
    }
}

5、编写 ShiroConfig 和 自定义Realm
ShiroConfig :

@Configuration
public class ShiroConfig {
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置securityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //设置登录的url
        shiroFilterFactoryBean.setLoginUrl("/login");
        //设置未授权的url
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");

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

        //定义filterChain,设置静态资源不拦截
        filterChainMap.put("/css/**", "anon");
        filterChainMap.put("/js/**", "anon");
        filterChainMap.put("/fonts/**", "anon");
        filterChainMap.put("/img/**", "anon");
        //配置退出过滤器,shiro已帮我们实现了
        filterChainMap.put("/logout", "logout");
        filterChainMap.put("/", "anon");
        //除以上url,其他url都必须通过认证,未认证默认自动访问loginUrl
        filterChainMap.put("/**", "authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);
        return shiroFilterFactoryBean;
    }

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

    @Bean
    public ShiroRealm shiroRealm() {
        ShiroRealm shiroRealm = new ShiroRealm();
        return shiroRealm;
    }
}

自定义Realm:

@Slf4j
public class ShiroRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

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

    /**
     * 登录认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 获取用户输入的用户名和密码
        String username = (String)authenticationToken.getPrincipal();
        String password = new String((char[]) authenticationToken.getCredentials()); //特别注意这里转String要这样写
        log.info("用户:{}, 密码:{}", username, password);
        //查询用户信息
        User user = userService.findUserByUserName(username);
        if (user == null) {
            throw new UnknownAccountException("用户名或密码错误");
        }
        if (!password.equals(user.getPassword())) {
            throw new IncorrectCredentialsException("用户名或密码错误");
        }
        if (user.getStatus().equals("0")) {
            throw new LockedAccountException("账号状态异常,请联系管理员!");
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, password, getName());
        return authenticationInfo;
    }
}

6、编写 controller 层

@Slf4j(topic = "UserController")
@Controller
public class UserController {

    @Autowired
    private UserService userService;
    
    @GetMapping("/login")
    public String login() {
        return "login";
    }

    @PostMapping("/login")
    @ResponseBody
    public ServerResponse login(@RequestParam("username") String userName, @RequestParam("password") String password) {
        //md5加密
        password = SecureUtil.md5(password);
        log.info("加密后的密码:{}", password);
        UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
        //获取Subject对象
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(token);
            return ServerResponse.createBySuccessMessage("登录成功");
        } catch (AuthenticationException e) {
            return ServerResponse.createByErrorMessage("登录失败");
        }
    }
}

7、编写一个极其简陋的登录页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
    <form action="/login" method="post">
        <input type="text" placeholder="用户名" name="username"><br>
        <input type="password" placeholder="密码" name="password"><br>
        <input type="submit" value="登录">
    </form>
</body>
</html>

8、开始测试,启动项目,访问http://localhost:8080/login 输入用户名Jone 和 密码123456
在这里插入图片描述
测试结果:
在这里插入图片描述
整合认证ok

(注意:)(1)ServerResponse 为自己写的相应类,可以上网搜一下。
(2)用了 h2内存数据库,这里贴一下在 yml 中的配置
spring:
  #h2内存数据库
  datasource:
    driver-class-name: org.h2.Driver
    schema: classpath:db/schema-h2.sql
    data: classpath:db/data-h2.sql
    url: jdbc:h2:mem:test
    username: root
    password: test
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值