Shiro(3)-整合springboot-mybatis-thymeleaf

springboot整合shiro,thymeleaf,mybatis

简介

在这里插入图片描述
在这里插入图片描述

shiro过滤器 anon authc

注意: shiro提供和多个默认的过滤器,我们可以用这些过滤器来配置控制指定url的权限:

配置缩写对应的过滤器功能
anonAnonymousFilter指定url可以匿名访问(访问时不需要认证授权)
authcFormAuthenticationFilter指定url需要form表单登录,默认会从请求中获取username、password,rememberMe等参数并尝试登录,如果登录不了就会跳转到loginUrl配置的路径。我们也可以用这个过滤器做默认的登录逻辑,但是一般都是我们自己在控制器写登录逻辑的,自己写的话出错返回的信息都可以定制嘛。
authcBasicBasicHttpAuthenticationFilter指定url需要basic登录
logoutLogoutFilter登出过滤器,配置指定url就可以实现退出功能,非常方便
noSessionCreationNoSessionCreationFilter禁止创建会话
permsPermissionsAuthorizationFilter需要指定权限才能访问
portPortFilter需要指定端口才能访问
restHttpMethodPermissionFilter将http请求方法转化成相应的动词来构造一个权限字符串,这个感觉意义不大,有兴趣自己看源码的注释
rolesRolesAuthorizationFilter需要指定角色才能访问
sslSslFilter需要https请求才能访问
userUserFilter需要已登录或“记住我”的用户才能访问

准备工作

create table `user`(
	`id` int not null AUTO_INCREMENT,
    `username` varchar(255) not null,
    `password` VARCHAR(255) not null,
     `address` varchar(255) DEFAULT null,
    PRIMARY KEY (`id`)
) ENGINE= INNODB DEFAULT charset=utf8;

insert into user values(1,'zhangsan','123','北京');
insert into user values(2,'lisi','456','上海');
INSERT INTO USER values(3,'wangerma','789','合肥');

login.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>用户登录</title>
</head>
<body>
<h1>用户登录</h1>
<form action="/login" method="post">
  <label for="username">用户名</label>
  <input id="username" type="text" name="username"> <br/>
  <label for="password">密码</label>
  <input id="password" type="text" name="password"> <br/>
  <input type="submit" value="登录">
</form>
</body>
</html>

1. pom引入资源

        <!--thymeleaf-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!--shrio-sprinboot整合依赖-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.5.3</version>
        </dependency>
        <!--mysql+mybatis-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.41</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.1</version>
        </dependency>

2. mybatis数据源配置application.yml

spring:
  datasource:
    url: jdbc:mysql://rm-bp18jitlw9a952i5x3o.mysql.rds.aliyuncs.com:3306/yeb?userSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: Kclkd2013

3. User实体类以及接口

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer id;
    private String username;
    private String password;
    private String address;
    private String salt;
}
@Mapper
public interface UserMapper {
    @Select("select * from user")
    List<User> getUsers();

    //根据用户名查询密码
    //判断注册的用户是否重复
    @Select("select password from user where username=#{username}")
    String getPasswordByUsername(String username);
}

4. 配置Shiro

在这里插入图片描述
ShiroConfig

@Configuration
public class ShiroConfig {

    // 1.创建shiroFilter, 负责拦截所有请求
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //给filter设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);

        //配置系统的受限资源
        Map<String,String> map = new HashMap<>();
        //      /**所有资源
        map.put("/login","anon"); // anon公共资源
        map.put("/**","authc"); // authc: 需要认证和授权
        //默认认证界面路径
        
        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

    // 2.创建安全管理器
    @Bean
    public DefaultWebSecurityManager getSecurityManager(@Qualifier("getRealm") Realm realm){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();

        //给安全管理器设置realm
        defaultWebSecurityManager.setRealm(realm);
        return defaultWebSecurityManager;
    }

    // 3.创建自定义realm
    @Bean
    public Realm getRealm(){
        return new CustomerRealm();
    }

}

CustomerRealm

public class CustomerRealm extends AuthorizingRealm {

    @Autowired
    UserMapper mUserMapper;

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    //身份认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("=====认证======");
        //首先拿到身份信息 username
        String principal = (String) authenticationToken.getPrincipal();

        //调用数据库,模拟查询操作
        if("zhangsan".equals(principal)){
            String password  = mUserMapper.getPasswordByUsername(principal);
            System.out.println("查询到的密码" + password);
            return new SimpleAuthenticationInfo(principal,password,this.getName());
        }
        return null;
    }
}

5.登录认证controller实现

@Controller
public class LoginController {
    @GetMapping("/login")
    public String toLogin(){
        return "login";
    }

    @GetMapping("/logout")
    public String logout(){
        Subject subject = SecurityUtils.getSubject();
        //在shiro的session中登出该用户
        subject.logout();
        return "redirect:login";
    }

    @PostMapping("/login")
    public String login(String username,String password){

        //获取主体对象 | 安全管理器@Bean已经自动注入
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(new UsernamePasswordToken(username,password));
            return "redirect:/index";
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("用户名错误");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("密码错误");
        }
        return "redirect:/login";
    }
}

6. 用户注册实现

注册页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>用户注册</title>
</head>
<body>
<h1>用户注册</h1>
<form action="/register" method="post">
  <label for="username">用户名</label>
  <input id="username" type="text" name="username"> <br/>
  <label for="password">密码</label>
  <input id="password" type="text" name="password"> <br/>
  <label for="address">地址</label>
  <input id="address" type="text" name="address"> <br/>
  <input type="submit" value="立即注册">
</form>
</body>
</html>

user接口

@Mapper
public interface UserMapper {
    @Select("select * from user")
    List<User> getUsers();
    
    //删除一个用户
    @Delete("delete from user where id = #{id}")
    void deleteUserById(Integer id);

    //根据用户名查询密码
    @Select("select password from user where username=#{username}")
    String getPasswordByUsername(String username);

    //注册,添加一个用户
    @Insert("insert into user(username,password,address,salt) values(#{username},#{password},#{address},#{salt})")
    void addUser(User user);

    //根据用户名,查看是否存该用户
    @Select("select count(*)  from user where username=#{username}")
    Integer getUserCountByName(String username);
    
    //根据用户名查询,返回一个对象
    @Select("select id,username,password,salt from user where username=#{username}")
    User getByName(String username);
}

用户service层

@Service
@Transactional
public class UserService {
    
    @Autowired
    UserMapper mUserMapper;

    //添加一个用户
    public void addUser(User user){
        //生成随机盐
        String salt = SaltUtils.getSalt(8);
        user.setSalt(salt);

        //明文密码进行md5+salt+hash散列
        Md5Hash md5Hash = new Md5Hash(user.getPassword(), salt, 1024);
        user.setPassword(md5Hash.toHex());
        mUserMapper.addUser(user);
    }

    //根据用户名,查看是否存该用户
    public Integer getUserCountByName(String username){
        return mUserMapper.getUserCountByName(username);
    }

    public List<User> getUsers(){
        return mUserMapper.getUsers();
    }

    //根据用户名查询密码
    public String getPasswordByUsername(String username){
        return mUserMapper.getPasswordByUsername(username);
    }
    
    //删除一个用户
    public void deleteUserById(Integer id){
        mUserMapper.deleteUserById(id);
    }
    
    //根据用户名查询,返回一个对象
    public User getByName(String username){
        return mUserMapper.getByName(username);
    }
}

Register Controller 控制层

@Controller
public class RegisterController {
    @Autowired
    UserService mUserService;
    
    @GetMapping("/register")
    public String toReg(){
        return "register";
    }

    @PostMapping("/register")
    public String register(User user){
        //查看是否已经存在该用户
        if(mUserService.getUserCountByName(user.getUsername()) != 0){
            System.out.println("用户名已经存在!");
            return "redirect:/register";
        }
        mUserService.addUser(user);
        System.out.println("已添加完成该用户");
        return "redirect:/login";
    }
}

7.用户登录实现(md5+salt+hash)

CustomerRealm

public class CustomerRealm extends AuthorizingRealm {

    @Autowired
    UserService mUserService;

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    //身份认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("=====认证======");
        //首先拿到身份信息 username
        String principal = (String) authenticationToken.getPrincipal();

        //查询有该用户是否存在
        boolean isExistUser;
        if(mUserService.getUserCountByName(principal) > 0){
            isExistUser = true;
        }

        //调用数据库,模拟查询操作
        if(true){

            User user = mUserService.getByName(principal);
            //查询密码
            String sqlPassword  = user.getPassword();
            //查询随机盐
            String sqlSalt = user.getSalt();

            System.out.println("查询到的密码" + sqlPassword);
            System.out.println("查询到的随机盐" + sqlSalt);

            /**
             *
             * 用户输入的password不需要任何处理
             * realm需要开启md5,设置,散列次数(HashedCredentialsMatcher)
             * 认证信息传入,加密过的密码,随机盐就可以了
             * shiro会自动根据用户数据的password进行md5和hash操作,然后再进行匹配
             */

            return new SimpleAuthenticationInfo(principal,sqlPassword, ByteSource.Util.bytes(sqlSalt),this.getName());
        }


        return null;
    }
}

盐工具类

public class SaltUtil {


    public static String getSalt(int n){

        char[] chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
        StringBuffer sb = new StringBuffer();
        for(int i = 0; i < n; i++){
            sb.append(chars[new Random().nextInt(chars.length)]);
        }
        return sb.toString();
    }
    
}

ShiroConfig配置实现md5+hash

@Configuration
public class ShiroConfig {

    // 1.创建shiroFilter, 负责拦截所有请求
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //给filter设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);

        //配置系统的受限资源
        Map<String,String> map = new HashMap<>();
        //      /**所有资源
        map.put("/login","anon"); // anon公共资源
        map.put("/register","anon"); // anon公共资源
        map.put("/public/**","anon"); // anon公共资源
        map.put("/**","authc"); // authc: 需要认证和授权
        //默认认证界面路径

        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

    // 2.创建安全管理器
    @Bean
    public DefaultWebSecurityManager getSecurityManager(@Qualifier("getRealm") Realm realm){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();

        //给安全管理器设置realm
        defaultWebSecurityManager.setRealm(realm);
        return defaultWebSecurityManager;
    }

    // 3.创建自定义realm
    @Bean
    public Realm getRealm(){
        CustomerRealm customerRealm = new CustomerRealm();
        HashedCredentialsMatcher hcm = new HashedCredentialsMatcher();
        hcm.setHashIterations(1024);
        hcm.setHashAlgorithmName("md5");
        customerRealm.setCredentialsMatcher(hcm);
        return customerRealm;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值