springboot用mybtis(可替换)整合shiro+thymeleaf+salt(密码加密)

17 篇文章 0 订阅
1 篇文章 0 订阅

1.创建项目并添加所需要的依赖
在这里插入图片描述
2.成功建完项目之后,在在pom中加入shiro与thymeleaf整合shiro的依赖

        <!--1.加入spring-shiro的依赖-->
        <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.5.3</version>
        </dependency>
        <!-- 2.shiro-thymeleaf-->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

3.所有的依赖添加成功以后,在去配置yml文件

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/db-shiro?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC

4.数据库的配置成功以后,再去添加相应的页面
首页-index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>首页</h1>
<H3 th:text="${msg}" style="color: red"></H3>
<h4><a th:href="@{/logout}">注销</a>|<a th:href="@{/toLogin}">登录</a></h4>
<hr>
<div 
    <a th:href="@{/toAdd}">添加</a>
</div>
<div >
    <a th:href="@{/toUpdate}">修改</a>
</div>
<div >
    <a th:href="@{/toUserList}">查看全部数据</a>
</div>

</body>
</html>

登录-login.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" >
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>login</h1>
<H3 th:text="${msg}" style="color: red"></H3>
<form th:action="@{/loginCheck}" method="post">
    用户名:<input name="name" type="text"/><br/>&nbsp;&nbsp;:<input name="pwd" type="password"/><br/>
    <input type="checkbox" name="rememberMe"/>记住我&nbsp;&nbsp;&nbsp;&nbsp;<a th:href="@{/toRegister}">注册新账号</a><br/>
    <input type="submit" value="登录"/>


</form>
</body>
</html>

注册-register.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" >
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>register</h1>
<form th:action="@{/register}" method="post">
    用户名:<input name="name" type="text"/><br/>&nbsp;&nbsp;:<input name="pwd" type="password"/><br/>
    <input type="submit" value="注册"/>
</form>
</body>
</html>

无权限页面–unauth.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<H1>该账号没有权限</H1>
</body>
</html>

建一个user的文件夹,在user的文件下面新建add,update,list三个页面
在这里插入图片描述

添加–add页面
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200507164256892.png

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>添加</h1>
</body>
</html>

修改–update页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>修改</h1>
</body>
</html>

显示列表页面–userList.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style type="text/css">
       p> span{
            background-color: lightgoldenrodyellow;

        }
    </style>
</head>
<body>
<h1>查看全部数据</h1>
<hr>
<h3><span>用户名</span>&nbsp;|&nbsp;<span>密码</span>&nbsp;|&nbsp;<span>权限</span></h3>
<p th:each="user:${userList}"><span th:text="${user.getName()}"></span>&nbsp;|&nbsp;<span th:text="${user.getPwd()}">
</span>&nbsp;|&nbsp;<span th:text="${user.getPerms()}"></span></p>
</body>
</html>

5.页面全部添加完之后再去建立,domain实体类,dao,service,controller等
实体类

//实体类必须要实现序列化
@Data
public class Tbuser implements Serializable {

    private long id;
    private String name;
    private String pwd;
    private String perms;
    private String salt;
}

数据表中的一些基本数据
在这里插入图片描述

dao层

@Mapper
@Repository
public interface UserDao {
    @Select("select * from tbuser")
    List<Tbuser> getUserList();
    @Select("select * from tbuser where name = #{name}")
    Tbuser getUserByName(String name);
    @Insert("insert into tbuser(name,pwd,salt) values (#{name},#{pwd},#{salt})")
    int addUser(Tbuser user);
}

service接口

public interface UserService {
    List<Tbuser> getUserList();

    Tbuser getUserByName(String name);

    int addUser(Tbuser tbuser);
}

实现类

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    UserDao userDao;
    @Override
    public List<Tbuser> getUserList() {
        List<Tbuser> list = userDao.getUserList();
        return list;
    }

    @Override
    public int addUser(Tbuser tbuser) {
        int i = userDao.addUser(tbuser);
        return i;
    }

    @Override
    public Tbuser getUserByName(String name) {
        Tbuser user = userDao.getUserByName(name);
        return user;
    }
}

controller层
IdnexController–用来做页面跳转的

@Controller
public class IndexController {
    @RequestMapping({"/", "index"})
    public String index() {
        return "index";
    }
    @RequestMapping("/toAdd")
    public String toAdd(){
        return "user/add";
    }
    @RequestMapping("/toUpdate")
    public String toUpdate(){
        return "user/update";
    }
    @RequestMapping("/toLogin")
    public String toLogin(){
        return "login";
    }
    @RequestMapping("/toRegister")
    public String toRegister(){
        return "register";
    }
    @RequestMapping("/toUnauth")
    public  String toUnauth() {
        return"unauth";
    }


}

UserController–用来做数据显示的

@Controller
public class UserController {

    @Autowired
    UserServiceImpl userService;

    @RequestMapping("/loginCheck")
    public String loginCheck(String name, String pwd,boolean rememberMe ,Model model) {
      model.addAttribute("msg", "用户登录成功!");
        return "index";//登录成功页面
    }

    @RequestMapping("/toUserList")
    public String getUserList(Model model) {
        List<Tbuser> userList = userService.getUserList();
        model.addAttribute("userList", userList);
        return "user/userList";
    }
    @RequestMapping("/register")
    public String register(Model model,Tbuser user) {
        userService.addUser(user);
        model.addAttribute("msg", "注册成功,请登录账号");
        return "login";
    }
    @RequestMapping("/logout")
    public String logout(Model model,Tbuser user) {
        model.addAttribute("msg", "用户注销成功!");
        return "login";
    }
}

6.项目的基本使用环境配置完成后,启动项目查看一下
首页-index,/
在这里插入图片描述

登录–login
在这里插入图片描述
登录成功后的页面
在这里插入图片描述
在这里插入图片描述
添加–toAdd
在这里插入图片描述
修改–toUpdate
在这里插入图片描述
查看数据-toUserList
在这里插入图片描述
注销
在这里插入图片描述
在这里插入图片描述
注册–register
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
7.项目的所有使用环境已经搭建成功,下面就开始创建shiro的配置文件

//shiro的配置文件
@Configuration
public class shiroConfig {

}

8.shiro的配置文件创建完成后,我们在编写的shiro的配置文件之前,还需要一个自定义的realm类,这个realm类是用来处理认证跟授权的

//自定义realm类,用来处理认证(登录)跟授权(给账号权限,有了权限可以访问指定的页面)
//继承AuthorizingRealm类,重写AuthorizationInfo方法跟AuthenticationInfo方法
public class UserRealm extends AuthorizingRealm {
    //Authorization:授权的意思
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了授权=>doGetAuthorizationInfo");
        return null;
    }
    //Authentication:认证的意思
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行了认证=>doGetAuthenticationInfo");
        return null;
    }
}

在这里插入图片描述
9.自定义的realm的类创建完成之后,我们在继续回到shiro的配置文件,开始编写shiro的配置文件

//shiro的配置文件,由下面三个核心组成,这三个方法是互相依赖,缺一不可
//1.自定义realm,(自定义了userRealm)
//2.配置DefaultWebSecurityManager(*核心)
//3.配置shiroFilterFactoryBean过滤器
@Configuration
public class shiroConfig {

    //1.创建realm对象,交给spring管理,
    @Bean
    public UserRealm userRealm() {
        UserRealm userRealm = new UserRealm();
        return userRealm;
    }
    //2.配置DefaultWebSecurityManager用来管理realm对象
    @Bean("securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);//管理Realm
        return securityManager;
    }
    //3.配置shiroFilterFactoryBean过滤器
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager webSecurityManager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(webSecurityManager);
        //设置shiro 内置的过滤器
        /*
         认证过滤器:
        anon(不认证也可以访问),authcBasic
        authc(必须认证后才可访问)
        user:必须拥有记住我功能
         授权过滤器:
         perms(指定资源需要哪些权限才可以访问)
         Roles:拥有某个角色权限才能访问
        * */
        //添加过滤器链
        Map<String, String> filterMap = new LinkedHashMap<>();
        filterMap.put("/toUpdate", "authc");
        filterMap.put("/toAdd", "authc");
        filterMap.put("/toUserList", "authc");
        //授权 正常情况下 未授权,会跳转到未授权的页面
        filterMap.put("/toUpdate", "perms[user:update]");
        filterMap.put("/toAdd", "perms[user:add]");
        filterMap.put("/toUserList", "perms[user:select]");

        //支持通配符
        /* filterMap.put("/user/*", "authc");*/

        //登录拦截
        bean.setFilterChainDefinitionMap(filterMap);
        //拦截后 没有登录跳转的页面
        bean.setLoginUrl("/toLogin");
        //未授权后,没有权限跳转的页面
        bean.setUnauthorizedUrl("/toUnauth");
        return bean;
    }
}

10.shiro的配置写完之后,我们先写登录认证的功能
在userController里编写logincheck接口

@RequestMapping("/loginCheck")
    public String loginCheck(String name, String pwd, boolean rememberMe , Model model) {
        //当shiro的一些基本配置完成,我们来写登录,写登录的时候需要用户输入的用户名跟密码(这里用户名不要输入重复的)
        //1.获取当前用户数据,subject对象是用来存储用户信息的
        Subject subject = SecurityUtils.getSubject();
        //2.把用户名跟密码生成token令牌
        UsernamePasswordToken token = new UsernamePasswordToken(name, pwd);
        //3.调用登录认证方法,所有的方法调用全部使用subject来调用,
        try {
            subject.login(token);//执行登录操作过程,调用这个方法,实际代码会走到realm类的认证方法中
            model.addAttribute("msg", "用户登录成功!");
            return "index";//登录成功页面
        } catch (UnknownAccountException e) { //登录失败的异常可以具体去百度
            model.addAttribute("msg", "用户名不存在");
            return "login";
        } catch (IncorrectCredentialsException e) {
            System.out.println("用户名密码错误的异常====>"+e.getMessage());
            model.addAttribute("msg", "账户密码错误");
            return "login";
        }
    }

在这里插入图片描述
11.编写完logincheck的接口之后,在去userRealm类中完善认证方法

//Authentication:认证的意思
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("执行了认证=>doGetAuthenticationInfo");
        //1.这个token就是loginCheck方法中传递过来的,里面有用户输入的用户名跟密码
        //userToken.getUsername()获取用户登录的用户名,可以输出查看比对
        UsernamePasswordToken userToken = (UsernamePasswordToken) token;

        //2.正确的账号密码 需要从数据库中取出,这里就要注入service去获取
        Tbuser user = userService.getUserByName(userToken.getUsername());
        if (null == user) {//判断用户是否存在
            return null;// 此处返回null
            // 会抛在loginCheck  声明的异常 UnknownAccountException(用户不存在)
        }
        //3.获取shiro中的session,
        // 登录成功后,首页一般都会显示我们的用户名,我们可以获取用户名放在session中,展示在页面上(如果未登录显示登录按钮)
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        session.setAttribute("user", user.getName());
        //4.密码认证,shiro帮我们进行登录认证,如果密码错误,会抛在loginCheck  声明的异常IncorrectCredentialsException(用户名密码错误)
        //返回对象的四个参数值
        //a.传入实体包下我们需要的user对象
        // 注意:此参数也可以通过subject.getPrincipal()方法获取—获取当前记录的用户,从这个用户对象进而再获取一系列的所需要的属性。
        //b.传入的是从数据库中获取到的password,然后再与token中的password进行对比,匹配上了就通过,匹配不上就报异常。
        //c.传入的是盐–用于加密密码对比。 若不需要,则可以设置为null
        //d.传入当前的realm的名字
        return new SimpleAuthenticationInfo(
                user,
                user.getPwd(),
                null,
                this.getName()
        );

    }

在这里插入图片描述
12.认证功能编写完成后,我们去在index的页面中添加一段代码

<span th:if="${session.user==null}"><a th:href="@{/toLogin}">登录</a></span>
    <span th:text="${session.user}"></span>

在这里插入图片描述

13.我们启动项目,测试一下我们的登录认证功能是否成功
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
情况1:用户名密码正确
在这里插入图片描述
在这里插入图片描述
情况2:用户名正确,密码错误
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
情况3:用户名错误
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
14.我们现在登录认证功能已经测试完毕,那我们输入正确的用户名,登录成功后到首页
在这里插入图片描述
在这里插入图片描述
为什么会没有权限呢,我们在shiro的配置文件中设置了
在这里插入图片描述
15.认证功能完善以后,我们就开始完善授权方法,编写UserRealm的授权方法

//Authorization:授权的意思
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了授权=>doGetAuthorizationInfo");
        //1.拿到当前登录的对象
        Subject subject = SecurityUtils.getSubject();
        //2.拿到TbUser对象
        Tbuser currentUser = (Tbuser) subject.getPrincipal();
        //***调用service层 ,查询用户的所有权限信息
        //***因为我们的用户表信息跟权限信息全部放在了一张表中,直接获取用户对象就可以,
        //***如果有用户表,权限表,角色表等多张表就需要在这里进行逻辑查找
        //3添加角色和权限
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //设置当前用户权限
        authorizationInfo.addStringPermission(currentUser.getPerms());
        return authorizationInfo;
    }

在这里插入图片描述
16.现在授权方法编写完成之后,我们在启动项目,去测试看看我们是否有权限
在这里插入图片描述
测试swj-add账号
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
测试swj账号,因为这个账号在数据库中有添加跟查看这两个权限,其他的两个账号都是单个权限,跟swj-add一样,无需在测试
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
17.我们的认证授权功能基本就算是写完了,在正常的访问网站中,当我们没有具体的权限功能的时候,菜单里都不会显示没有权限的功能,比如
在这里插入图片描述
18.在shiro的配置里填写整合shiro 和thymeleaf的bean

//整合shiroDialect 用来整合shiro 和thymeleaf
    @Bean
    public ShiroDialect getShiroDialect() {
        return new ShiroDialect();
    }

在这里插入图片描述
19.配置写完之后我们去首页-index页面去添加整合shiro 和thymeleaf的标签代码

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro" >
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>首页</h1>
<H3 th:text="${msg}" style="color: red"></H3>
<h4><a th:href="@{/logout}">注销</a>|<span th:if="${session.user==null}"><a th:href="@{/toLogin}">登录</a></span>
    <span th:text="${session.user}"></span></h4>
<hr>
<div shiro:hasPermission="user:add">
    <a th:href="@{/toAdd}">添加</a>
</div>
<div shiro:hasPermission="user:update">
    <a th:href="@{/toUpdate}">修改</a>
</div>
<div shiro:hasPermission="user:select">
    <a th:href="@{/toUserList}">查看全部数据</a>
</div>

</body>
</html>

在这里插入图片描述
20.启动项目测试,看看页面上是否有变化,以swj账号为例子测试
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
21.现在的shiro的认证跟授权已经全部完善,当我们退出登录的时候,只是一个页面跳转,没有注销的功能,我们要在UserController里面完善我们的注销功能

 //注销
    @RequestMapping("/logout")
    public String logout(Model model){
        //1.获取用户
        Subject subject = SecurityUtils.getSubject();
        //2.注销清除所有痕迹
        subject.logout();
        model.addAttribute("msg", "注销成功!请重新登录");
        return "login";
    }

在这里插入图片描述
22.注销编写完成之后,我们在继续启动项目测试
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
23.注销功能也写完了,我们平时的账号跟密码在数据库中,密码都是密文,这样也是为了我们的账户安全考虑,有一天,数据库被别人看到了,就知道了我们的密码,但是我们的密码都是加密过的在数据库中,就算数据库的密码泄露,我们的账号也是安全的
在这里插入图片描述
我们既然要对密码进行加密,就要在注册新账号的时候,对密码进行加密处理,所以我们要现在UserServiceImpl中处理密码

  @Override
    public int addUser(Tbuser tbuser) {
        //在这里开始处理密码
        String salt = UUID.randomUUID().toString();//利用uuid类生成的盐
        String s = new Md5Hash(tbuser.getPwd(),salt,1000).toBase64();//1000代表跌迭代1000次
        tbuser.setPwd(s);
        tbuser.setSalt(salt);
        int i = userDao.addUser(tbuser);
        return i;
    }

在这里插入图片描述
24.注册新账号的逻辑编写完成以后,我们再去shiro的编写类添加一个bean

 // 密码加密
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashIterations(1000);//迭代方式
        hashedCredentialsMatcher.setHashAlgorithmName("md5");//加密方式
        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(false);//true=hex格式,false=base64格式
        return hashedCredentialsMatcher;
    }

在这里插入图片描述
25.加密的bean编写完之后,我们把这个bean当作参数注入给realm对象

 @Bean
    public UserRealm userRealm(HashedCredentialsMatcher matcher) {
        UserRealm userRealm = new UserRealm();
      userRealm.setCredentialsMatcher(matcher);//加密比较器
        return userRealm;
    }

在这里插入图片描述
26.我们在回到realm类的认证方法中,把盐给放进判断密码的返回的对象中
在这里插入图片描述

   ByteSource.Util.bytes(user.getSalt()),//放盐salt

在这里插入图片描述
27.加密处理完成以后,我们启动项目进行测试
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们在登录一下刚刚注册的新账号,看看能否注册成功
在这里插入图片描述
新账号登录成功,就代表我们之前的老账号,没有加密的就登录失败
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
28.记住我功能

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yzhSWJ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值