第104天学习打卡(SpringBoot 开启记住我功能和定制首页 Shiro)

开启记住我功能 和定制首页

开启记住我功能 和定制首页方法一:

SecurityConfig.java

        //开启了注销功能  跳到首页
        http.logout().logoutSuccessUrl("/");

        //开启记住我功能  本质是一个cookie的实现
        http.rememberMe();

login.html修改的内容:

<div style="text-align: center">
            <h1 class="header">登录h1>
        div>

        <div class="ui placeholder segment">
            <div class="ui column very relaxed stackable grid">
                <div class="column">
                    <div class="ui form">
                        <form th:action="@{/toLogin}" method="post">
                            <div class="field">
                                <label>Usernamelabel>
                                <div class="ui left icon input">
                                    <input type="text" placeholder="Username" name="username">
                                    <i class="user icon">i>
                                div>
                            div>
                            <div class="field">
                                <label>Passwordlabel>
                                <div class="ui left icon input">
                                    <input type="password" name="password">
                                    <i class="lock icon">i>
                                div>
                            div>
                            <input type="submit" class="ui blue submit button"/>
                        form>
                    div>
                div>
            div>
        div>

方法二

SecurityConfig.java

  http.formLogin().loginPage("/toLogin").loginProcessingUrl("/login");

login.html

    <div class="ui placeholder segment">
            <div class="ui column very relaxed stackable grid">
                <div class="column">
                    <div class="ui form">
                        <form th:action="@{/login}" method="post">
                            <div class="field">
                                <label>Usernamelabel>
                                <div class="ui left icon input">
                                    <input type="text" placeholder="Username" name="username">
                                    <i class="user icon">i>
                                div>
                            div>
                            <div class="field">
                                <label>Passwordlabel>
                                <div class="ui left icon input">
                                    <input type="password" name="password">
                                    <i class="lock icon">i>
                                div>
                            div>
                            <input type="submit" class="ui blue submit button"/>
                        form>
                    div>
                div>
            div>
        div>

在这个页面进行登录:

第104天学习打卡(SpringBoot 开启记住我功能和定制首页 Shiro)_第1张图片

方式三: 修改login.html中的username 为user password为pwd 时的登录:

SecurityConfig.java

  http.formLogin().loginPage("/toLogin").usernameParameter("user").passwordParameter("pwd").loginProcessingUrl("/login");

login.html

<div class="ui placeholder segment">
            <div class="ui column very relaxed stackable grid">
                <div class="column">
                    <div class="ui form">
                        <form th:action="@{/login}" method="post">
                            <div class="field">
                                <label>Usernamelabel>
                                <div class="ui left icon input">
                                    <input type="text" placeholder="Username" name="user">
                                    <i class="user icon">i>
                                div>
                            div>
                            <div class="field">
                                <label>Passwordlabel>
                                <div class="ui left icon input">
                                    <input type="password" name="pwd">
                                    <i class="lock icon">i>
                                div>
                            div>
                            <input type="submit" class="ui blue submit button"/>
                        form>
                    div>
                div>
            div>
        div>

记住我的自定义接收前端的参数

SecurityConfig.java

 //开启记住我功能  本质是一个cookie的实现,默认保存两周   自定义接收前端的参数
        http.rememberMe().rememberMeParameter("remember");

login.html

  <div class="field">
                              <input type="checkbox" name="remember"> 记住我
                          div>

完整代码

SecurityConfig.java

package com.kuang.config;

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

//AOP横切  拦截器
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
     
// 授权
    //链式编程
    @Override
    protected void configure(HttpSecurity http) throws Exception {
     
        //首页所有人可以访问   功能页只有对应有权限的人才能访问
        //请求授权的规则
        // "/"代表访问首页
        http.authorizeRequests().antMatchers("/").permitAll()
                .antMatchers("/level1/**").hasRole("vip1")
                .antMatchers("/level2/**").hasRole("vip1")
                .antMatchers("/level3/**").hasRole("vip1");

        //没有权限默认会到登录页  需要开启登录的页面
        // /login页面
        //定制登录页loginPage("/toLogin")

       // http.formLogin().loginPage("/toLogin");  方法一
        //http.formLogin().loginPage("/toLogin").loginProcessingUrl("/login"); 方法二
        http.formLogin().loginPage("/toLogin").usernameParameter("user").passwordParameter("pwd").loginProcessingUrl("/login");

        //防止网站攻击
        http.csrf().disable();//关闭crsf     crsf:防止跨站请求伪造


        //开启了注销功能  跳到首页
        http.logout().logoutSuccessUrl("/");

        //开启记住我功能  本质是一个cookie的实现,默认保存两周   自定义接收前端的参数
      //  http.rememberMe();//方式一
        http.rememberMe().rememberMeParameter("remember");//方式二


    }
//认证
    //密码编码:PasswordEncoder
    //在Spring Security 5.0+ 新增了很多的加密方法
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
     

        //这些数据正常应该从数据库中读
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("kuangshen").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
                .and()
                .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
                .and()
                .withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");


    }
}

login.html


<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <title>登录title>
    
    <link href="https://cdn.bootcss.com/semantic-ui/2.4.1/semantic.min.css" rel="stylesheet">
head>
<body>


<div class="ui container">

    <div class="ui segment">

        <div style="text-align: center">
            <h1 class="header">登录h1>
        div>

        <div class="ui placeholder segment">
            <div class="ui column very relaxed stackable grid">
                <div class="column">
                    <div class="ui form">
                        <form th:action="@{/login}" method="post">
                            <div class="field">
                                <label>Usernamelabel>
                                <div class="ui left icon input">
                                    <input type="text" placeholder="Username" name="user">
                                    <i class="user icon">i>
                                div>
                            div>
                            <div class="field">
                                <label>Passwordlabel>
                                <div class="ui left icon input">
                                    <input type="password" name="pwd">
                                    <i class="lock icon">i>
                                div>
                            div>
                          <div class="field">
                              <input type="checkbox" name="remember"> 记住我
                          div>
                            <input type="submit" class="ui blue submit button"/>
                        form>
                    div>
                div>
            div>
        div>

        <div style="text-align: center">
            <div class="ui label">
                i>注册
            div>
            <br><br>
            <small>blog.kuangstudy.comsmall>
        div>
        <div class="ui segment" style="text-align: center">
            <h3>Spring Security Study by 秦疆h3>
        div>
    div>


div>

<script th:src="@{/qinjiang/js/jquery-3.1.1.min.js}">script>
<script th:src="@{/qinjiang/js/semantic.min.js}">script>

body>
html>

Shiro

1.1 什么是Shiro

  • Apache Shiro是Java的安全(权限)框架
  • Shiro可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在JavaEE环境。
  • Shiro可以完成,认证,授权,加密,会话4管理,Web集成,缓存等。
  • 官网地址:https://shiro.apache.org/

下载地址:https://github.com/apache/shiro

第104天学习打卡(SpringBoot 开启记住我功能和定制首页 Shiro)_第2张图片

1.2有哪些功能

  • Authentication:身份认证、登录、验证用户是不是拥有相应的身份;
  • Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限,即判断用户能否进行什么操作。如:验证某个用户是否拥有某个角色,或者细粒度的验证某个用户对某个资源是否具有某个权限!
  • Session Manager: 会话管理,即用户登录后就是第一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通的JavaSE环境,也可以是Web环境。
  • Cryptography:加密,保护数据的安全性,如密码存储到数据库中,而不是明文存储;
  • Web Support: Web支持,可以非常容易的集成到Web环境;
  • Caching:缓存,比如用户登录后,其用户信息,拥有的角色,权限不必每次去查,这样可以提高效率
  • Concurrency:Shiro支持多线程应用的并发验证,即,如在一个线程中开启另一个线程,能把权限自动的传播过去。
  • Testing:提高测试支持;
  • Run As:允许用户假装为另一个用户(如果他们允许)的身份进行访问;
  • Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。

1.3 Shiro架构(外部)

从外部来看Shiro,即从程序角度来观察如何使用shiro完成工作:

第104天学习打卡(SpringBoot 开启记住我功能和定制首页 Shiro)_第3张图片

  • subject:应用代码直接交互的对象是Subject,也就是说Shiro的对外API核心就是Subject, Subject代表了当前的用户,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等,与Subject的所有交互都会委托给SecurityManager;Subject其实是一个门面, SecurityManager才是实际的执行者。
  • SecurityManager:安全管理者,即所有与安全有关的操作都会与SecurityManager交互,并且它管理所有的Subject,可以看出它是Shiro的核心,它负责与Shiro的其他组件进行交互,它相当于SpringMVC的DispatcherServlet的角色
  • Realm:Shiro从Realm获取安全数据(如用户,角色,权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较;也需要从Realm得到用户相应的角色权限,进行验证用户的操作是否能够进行,可以把Realm看成DataSource

1.4 Shiro架构(内部)

第104天学习打卡(SpringBoot 开启记住我功能和定制首页 Shiro)_第4张图片

  • Subject:任何可以与应用交互的用户;
  • Security Manager: 相当于SpringMVC中的DispatcherServlet;是Shiro的心脏,所有具体的交互都通过Security Manager进行控制,它管理着所有的Subject,且负责进行认证,授权,会话及缓存的管理。
  • Authenticator:负责Subject认证,是一个扩展点,可以自定义实现,可以使用认证策略(Authentication Strategy),即什么情况下算用户认证通过了;
  • Realm: 可以有一个或者多个的realm,可以任务是安全实体数据源,即用于获取安全实体的,可以用JDBC实现,也可以是内存实现等等,由用户提供;所以一般在应用中都需要实现自己的realm
  • SessionManager:管理Session生命周期的组件,而Shiro并不仅仅可以用在Web环境,也可以用在普通的JavaSE环境中
  • CacheManager:缓存控制器,用来管理用户,角色,权限等缓存的;因为这些数据基本上很少改变,放到缓存中后可以提高访问的性能
  • Cryptography:密码模块,Shiro提高了一些常见的加密组件用于密码加密,解密等

1.导入依赖:

官网下载地址:https://shiro.apache.org/download.html#latestGit

https://github.com/apache/shiro/tree/main/samples/quickstart

pom.xml


<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.0modelVersion>
    <groupId>com.kuanggroupId>
    <artifactId>shiro-springbootartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <name>shiro-springbootname>
    <description>Demo project for Spring Bootdescription>

    <properties>
        <java.version>1.8java.version>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASEspring-boot.version>
    properties>

    <dependencies>

        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
        dependency>


        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
        dependency>

        <dependency>
            <groupId>log4jgroupId>
            <artifactId>log4jartifactId>
            <version>1.2.17version>
        dependency>

        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>druidartifactId>
            <version>1.2.6version>
        dependency>

        <dependency>
            <groupId>org.mybatis.spring.bootgroupId>
            <artifactId>mybatis-spring-boot-starterartifactId>
            <version>2.1.4version>
        dependency>
        
        <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-springartifactId>
            <version>1.7.1version>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

        <dependency>
            <groupId>org.thymeleafgroupId>
            <artifactId>thymeleaf-spring5artifactId>
        dependency>
        <dependency>
            <groupId>org.thymeleaf.extrasgroupId>
            <artifactId>thymeleaf-extras-java8timeartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintagegroupId>
                    <artifactId>junit-vintage-engineartifactId>
                exclusion>
            exclusions>
        dependency>
    dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-dependenciesartifactId>
                <version>${spring-boot.version}version>
                <type>pomtype>
                <scope>importscope>
            dependency>
        dependencies>
    dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-compiler-pluginartifactId>
                <version>3.8.1version>
                <configuration>
                    <source>1.8source>
                    <target>1.8target>
                    <encoding>UTF-8encoding>
                configuration>
            plugin>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
                <version>2.3.7.RELEASEversion>
                <configuration>
                    <mainClass>com.kuang.ShiroSpringbootApplicationmainClass>
                configuration>
                <executions>
                    <execution>
                        <id>repackageid>
                        <goals>
                            <goal>repackagegoal>
                        goals>
                    execution>
                executions>
            plugin>
        plugins>
    build>

project>

2.配置文件

resources

log4j.properties

log4j.rootLogger=INFO, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n

# General Apache libraries
log4j.logger.org.apache=WARN

# Spring
log4j.logger.org.springframework=WARN

# Default Shiro logging
log4j.logger.org.apache.shiro=INFO

# Disable verbose logging
log4j.logger.org.apache.shiro.util.ThreadContext=WARN
log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN

shiro.ini

[users]
# user 'root' with password 'secret' and the 'admin' role
root = secret, admin
# user 'guest' with the password 'guest' and the 'guest' role
guest = guest, guest
# user 'presidentskroob' with password '12345' ("That's the same combination on
# my luggage!!!" ;)), and role 'president'
presidentskroob = 12345, president
# user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz'
darkhelmet = ludicrousspeed, darklord, schwartz
# user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz'
lonestarr = vespa, goodguy, schwartz

# -----------------------------------------------------------------------------
# Roles with assigned permissions
#
# Each line conforms to the format defined in the
# org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc
# -----------------------------------------------------------------------------
[roles]
# 'admin' role has all permissions, indicated by the wildcard '*'
admin = *
# The 'schwartz' role can do anything (*) with any lightsaber:
schwartz = lightsaber:*
# The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with
# license plate 'eagle5' (instance specific id)
goodguy = winnebago:drive:eagle5

提取出来的对象

Spirng Security都有

//获取当前的用户对象 Subject
Subject currentUser = SecurityUtils.getSubject();

 //通过当前用户拿到Session
        Session session = currentUser.getSession();
        
 //判断当前用户是否被认证
   if (!currentUser.isAuthenticated())
   //获得当前用户的一个认证
   currentUser.getPrincipal() 
   //获得这个用户是否拥有什么角色
   currentUser.hasRole("schwartz")
   //获得当前用户的一些权限
   currentUser.isPermitted("lightsaber:wield")
    //注销
        currentUser.logout();

Quickstart.java


import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.util.Factory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * Simple Quickstart application showing how to use Shiro's API.
 *
 * @since 0.9 RC2
 */
public class Quickstart {
     

    private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);


    public static void main(String[] args) {
     

        // The easiest way to create a Shiro SecurityManager with configured
        // realms, users, roles and permissions is to use the simple INI config.
        // We'll do that by using a factory that can ingest a .ini file and
        // return a SecurityManager instance:

        // Use the shiro.ini file at the root of the classpath
        // (file: and url: prefixes load from files and urls respectively):
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();

        // for this simple example quickstart, make the SecurityManager
        // accessible as a JVM singleton.  Most applications wouldn't do this
        // and instead rely on their container configuration or web.xml for
        // webapps.  That is outside the scope of this simple quickstart, so
        // we'll just do the bare minimum so you can continue to get a feel
        // for things.
        SecurityUtils.setSecurityManager(securityManager);

        // Now that a simple Shiro environment is set up, let's see what you can do:

        // get the currently executing user:

        //获取当前的用户对象 Subject
        Subject currentUser = SecurityUtils.getSubject();

        // Do some stuff with a Session (no need for a web or EJB container!!!)
        //通过当前用户拿到Session
        Session session = currentUser.getSession();
        session.setAttribute("someKey", "aValue");
        String value = (String) session.getAttribute("someKey");
        if (value.equals("aValue")) {
     
            log.info(" Subject=>session[" + value + "]");
        }

        // let's login the current user so we can check against roles and permissions:
        //判断当前用户是否被认证

        //Token令牌 获取了用户User [lonestarr] logged in successfully.
        if (!currentUser.isAuthenticated()) {
     
            UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
            token.setRememberMe(true); //设置记住我
            try {
     
                currentUser.login(token); //执行了登录操作
            } catch (UnknownAccountException uae) {
     
                log.info("There is no user with username of " + token.getPrincipal());
            } catch (IncorrectCredentialsException ice) {
     
                log.info("Password for account " + token.getPrincipal() + " was incorrect!");
            } catch (LockedAccountException lae) {
     
                log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                        "Please contact your administrator to unlock it.");
            }
            // ... catch more exceptions here (maybe custom ones specific to your application?
            catch (AuthenticationException ae) {
     
                //unexpected condition?  error?
            }
        }

        //say who they are:
        //print their identifying principal (in this case, a username):
        log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");

        //test a role:
        if (currentUser.hasRole("schwartz")) {
     
            log.info("May the Schwartz be with you!");
        } else {
     
            log.info("Hello, mere mortal.");
        }
        //粗粒度
        //test a typed permission (not instance-level)
        if (currentUser.isPermitted("lightsaber:wield")) {
     
            log.info("You may use a lightsaber ring.  Use it wisely.");
        } else {
     
            log.info("Sorry, lightsaber rings are for schwartz masters only.");
        }
         //细粒度
        //a (very powerful) Instance Level permission:
        if (currentUser.isPermitted("winnebago:drive:eagle5")) {
     
            log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  " +
                    "Here are the keys - have fun!");
        } else {
     
            log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
        }
        //注销
        //all done - log out!
        currentUser.logout();
       //结束
        System.exit(0);
    }
}

在pom.xml中配置的依赖


<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.0modelVersion>
    <groupId>com.kuanggroupId>
    <artifactId>shiro-springbootartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <name>shiro-springbootname>
    <description>Demo project for Spring Bootdescription>

    <properties>
        <java.version>1.8java.version>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASEspring-boot.version>
    properties>

    <dependencies>




        <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-springartifactId>
            <version>1.7.1version>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

        <dependency>
            <groupId>org.thymeleafgroupId>
            <artifactId>thymeleaf-spring5artifactId>
        dependency>
        <dependency>
            <groupId>org.thymeleaf.extrasgroupId>
            <artifactId>thymeleaf-extras-java8timeartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintagegroupId>
                    <artifactId>junit-vintage-engineartifactId>
                exclusion>
            exclusions>
        dependency>
    dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-dependenciesartifactId>
                <version>${spring-boot.version}version>
                <type>pomtype>
                <scope>importscope>
            dependency>
        dependencies>
    dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-compiler-pluginartifactId>
                <version>3.8.1version>
                <configuration>
                    <source>1.8source>
                    <target>1.8target>
                    <encoding>UTF-8encoding>
                configuration>
            plugin>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
                <version>2.3.7.RELEASEversion>
                <configuration>
                    <mainClass>com.kuang.ShiroSpringbootApplicationmainClass>
                configuration>
                <executions>
                    <execution>
                        <id>repackageid>
                        <goals>
                            <goal>repackagegoal>
                        goals>
                    execution>
                executions>
            plugin>
        plugins>
    build>

project>

连接数据库

第104天学习打卡(SpringBoot 开启记住我功能和定制首页 Shiro)_第5张图片

jdbc:mysql://localhost:3306/?serverTimezone=GMT

application.yml

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource

    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true


    filters: stat,wall,log4j2
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500


config

ShiroConfig.java

package com.kuang.config;

import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
     

    //ShiroFilterFactory  第三步
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
     
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();

        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);

        //添加shiro的内置过滤器
        /*
          anon : 无需认证就可以访问
          authc:必须认证了才可能访问
          user : 必须拥有 记住我,功能才能用
          perms:拥有对某个资源的权限才能访问
          role:拥有某个角色权限才能访问
         */
        //拦截
        Map<String, String> filterMap = new LinkedHashMap<>();

        //授权,正常情况下,没有授权会跳转到未授权页面
        filterMap.put("/user/add","perms[user:add]");
        filterMap.put("/user/update","perms[user:update]");
//        filterMap.put("/user/add","authc"); // 方法1
//        filterMap.put("/user/update","authc");
//把上面两行代码合成一个
        filterMap.put("/user/*","authc");
        bean.setFilterChainDefinitionMap(filterMap);
        //设置登录的请求
        bean.setLoginUrl("/toLogin");
        //未授权页面
        bean.setUnauthorizedUrl("/noauth");

        return bean;
    }


    //DefaultWebSecurityManager  第二步
    @Bean(name="securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
     
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联UserRealm
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    //创建 realm对象, 需要自定义 第一步
    @Bean
    public UserRealm userRealm(){
     
        return new UserRealm();
    }

}

UserRealm.java

package com.kuang.config;

import com.kuang.pojo.User;
import com.kuang.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;

//自定义的 UserRealm   extends AuthorizingRealm
public class UserRealm extends AuthorizingRealm {
     
    @Autowired
    UserService userService;


    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
     
        System.out.println("执行了=>授权doGetAuthorizationInfo");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermission("user:add");
        //拿到当前登录的这个对象
        Subject subject = SecurityUtils.getSubject();
        User currentUser = (User) subject.getPrincipal();//拿到user对象

        //设置当前用户的权限
        info.addStringPermission(currentUser.getPerms());


        return info;
    }
//认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
     
        System.out.println("执行了=>认证doGetAuthenticationInfo");

//        //用户名,密码 数据库中取
//        String name = "root";
//        String password = "123456";

        UsernamePasswordToken userToken = (UsernamePasswordToken) token;

        //连接真实数据库
        User user = userService.queryUserByName(userToken.getUsername());
        if(user==null){
     
            //没有这个人
            return null; //爆出异常UnknownAccountException

        }
//        if (!userToken.getUsername().equals(name)){
     
//            return null;//抛出异常  UnknownAccountException  用户名不存在
//
//        }

        //可以加密:MD5  MD5盐值加密  MD5不可逆

        //密码认证,shiro做   加密

        return new SimpleAuthenticationInfo(user,user.getPwd(),"");



    }
}

controller

MyController.java

package com.kuang.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class MyController {
     
    //一般情况下首页不止一个所以这样写
    @RequestMapping({
     "/","/index"})
    public String toIndex(Model model){
     
        model.addAttribute("msg","hello,Shiro");
        return "index";//跳转到index页面
    }
@RequestMapping("/user/add")
    public String add(){
     
        return "user/add";
    }

    @RequestMapping("/user/update")
    public String update(){
     
        return "user/update";
    }

    @RequestMapping("/toLogin")
    public String toLogin(){
     
        return "login";
    }
@RequestMapping("/login")
    public String login(String username,String password,Model model){
     
        //获取当前的用户
        Subject subject = SecurityUtils.getSubject();

        //封装用户的登录数据
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        //登录令牌   执行登录方法,如果没有异常就说明OK了
    try {
     
        subject.login(token);
        return "index";
    } catch (UnknownAccountException e) {
      //用户名不存在
        model.addAttribute("msg","用户名错误");
        return "login";
    }catch (IncorrectCredentialsException e){
     //密码不存在
        model.addAttribute("msg", "密码错误");
        return "login";

    }
}

@RequestMapping("/noauth")
@ResponseBody
    public String unauthorized(){
     
        return "未经授权无法访问此页面";

}
}

mapper

UserMapper.java

package com.kuang.mapper;

import com.kuang.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

@Repository
@Mapper
public interface UserMapper {
     
    public User queryUserByName(String name);

}

pojo

User.java

package com.kuang.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
     

    private int id;
    private String name;
    private String pwd;
    private String perms;
}

service

UserService.java

package com.kuang.service;

import com.kuang.pojo.User;

public interface UserService {
     
    public User queryUserByName(String name);
}

UserServiceImpl.java

package com.kuang.service;

import com.kuang.mapper.UserMapper;
import com.kuang.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService{
     
    @Autowired
    UserMapper userMapper;

    @Override
    public User queryUserByName(String name) {
     
        return userMapper.queryUserByName(name);
    }
}

resources mapper

UserMapper.xml



<mapper namespace="com.kuang.mapper.UserMapper">

   <select id="queryUserByName" parameterType="String" resultType="User">
       select * from mybatis.user where name = #{name}
   select>
mapper>

resources templates user

add.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<h1>addh1>
body>
html>

update.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<h1>updateh1>
body>
html>

index.html


<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<h1>首页h1>
<p th:text="${msg}">p>

<hr>
<a th:href="@{/user/add}">adda> | <a th:href="@{/user/update}">updatea>
body>
html>

login.html


<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<h1>登录h1>
<hr>
<p th:text="${msg}" style="color: red">p>
<form th:action="@{/login}">
    <p>用户名:<input type="text" name="username">p>
    <p>密码:<input type="text" name="password">p>
    <p><input type="submit">p>

form>
body>
html>

application.properties

mybatis.type-aliases-package=com.kuang.pojo
mybatis.mapper-locations=classpath:mapper/*.xml


application.yml

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource

    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true


    filters: stat,wall,log4j2
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500


test

package com.kuang;

import com.kuang.service.UserService;
import com.kuang.service.UserServiceImpl;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class ShiroSpringbootApplicationTests {
     
    @Autowired
    UserServiceImpl userService;

    @Test
    void contextLoads() {
     
        System.out.println(userService.queryUserByName("小明"));
    }

}

增加了一个字段在Mysql中:

第104天学习打卡(SpringBoot 开启记住我功能和定制首页 Shiro)_第6张图片

第104天学习打卡(SpringBoot 开启记住我功能和定制首页 Shiro)_第7张图片

你可能感兴趣的:(shiro)