spring boot----JDBC、druid、mybatis、spring Security、shiro

spring boot----JDBC、druid、mybatis、spring Security、shiro,第1张

1.整合JDBC 1.1SpringData

对于数据访问层,无论是 SQL(关系型数据库) 还是 NOSQL(非关系型数据库),Spring Boot 底层都是采用 Spring Data 的方式进行统一处理,Spring Data 也是 Spring 中与 Spring Boot、Spring Cloud 等齐名的知名项目。

  • Sping Data 官网:https://spring.io/projects/spring-data

  • 数据库相关的启动器 :可以参考官方文档:https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/htmlsingle/#using-boot-starter

1.2连接数据库

1.新建一个项目引入基础模块:

2.编写yaml配置文件连接数据库

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    password: 1234
    #?serverTimezone=UTC解决时区的报错
    url: jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&haracterEncoding=UTF-8&serverTimezone=UTC
    username: root

3.测试

@SpringBootTest
class Springboot05DataApplicationTests {
    @Autowired
    DataSource dataSource;
    @Test
    void contextLoads() throws SQLException {
        //查看默认数据源
        System.out.println(dataSource.getClass());
        //连接数据库
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
        connection.close();
    }
}

HikariDataSource 号称 Java WEB 当前速度最快的数据源,相比于传统的 C3P0 、DBCP、Tomcat jdbc 等连接池更加优秀。

 

1.3JDBCTemplate

xxxxTemplate:spring boot已经配置好的模板bean,拿来即用CRUD。

源码位置:

JdbcTemplate主要提供以下几类方法:

  • execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句
  • update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句
  • query方法及queryForXXX方法:用于执行查询相关语句
  • call方法:用于执行存储过程、函数相关语句

测试:

@RestController
public class JDBCController {
    @Autowired
    JdbcTemplate jdbcTemplate;
    //查询数据库的全部信息
    //我们没写实体类就用一个万能的Map
    @GetMapping("/list")
    public List<Map<String,Object>> query(){
        String sql="select * from mybatis.user";
        List<Map<String, Object>> mapList = jdbcTemplate.queryForList(sql);
        return mapList;
    }
    @GetMapping("/addlist")
    public String add(){
        String sql="insert into mybatis.user (id,user.name,pwd) values(1,'嘿嘿嘿','9uidj')";
        jdbcTemplate.update(sql);
        return "ok";
    }
    @GetMapping("/deletelist/{id}")
    public String delete(@PathVariable int id){
        String sql="delete from mybatis.user where id=?";
        jdbcTemplate.update(sql,id);
        return "ok1";
    }
    @GetMapping("/updatelist/{id}")
    public String update(@PathVariable int id){
        String sql="update mybatis.user set user.name=?,pwd=? where id="+id;
        Object[] objects = new Object[2];
        objects[0]="啦啦啦";
        objects[1]="wef";
        jdbcTemplate.update(sql,objects);
        return "ok2";
    }
}

 
 

2.整合Druid(德鲁伊) 2.1简介及属性

Druid 是阿里巴巴开源平台上一个数据库连接池实现,结合了 C3P0、DBCP 等 DB 池的优点,同时加入了日志监控。

Druid 可以很好的监控 DB 池连接和 SQL 的执行情况,天生就是针对监控而生的 DB 连接池。

Github地址:https://github.com/alibaba/druid/

 

首先要导入依赖:


<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>druidartifactId>
    <version>1.2.8version>
dependency>
spring:
  datasource:
    # 指定数据源
    type: com.alibaba.druid.pool.DruidDataSource

测试结果:

 

一些配置:其中filters: stat,wall,log4j是其强大之处

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    password: 1234
    #?serverTimezone=UTC解决时区的报错
    url: jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&haracterEncoding=UTF-8&serverTimezone=UTC
    username: root
    type: com.alibaba.druid.pool.DruidDataSource

    #Spring Boot 默认是不注入这些属性值的,需要自己绑定
    #druid 数据源专有配置
    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:监控统计、log4j:日志记录、wall:防御sql注入
    #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
    #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

 

2.2监控的配置类

在config包下建一个DuridConfig 配置类

@Configuration
public class DruidConfig {
    //与yaml配置文件绑定
    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource DuridDatasource(){
        return new DruidDataSource();
    }

    //后台监控,相当于web.xml
    //因为springboot内置了servlet,没有web.xml,所以替代方法就是去配置一个类
    @Bean
    public ServletRegistrationBean StatViewServlet(){
        ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(),"/druid/*");
        
        //后台需要有人登录,账号密码设置
        HashMap<String, String> initParameters = new HashMap<>();
        //增加配置
        initParameters.put("loginUsername","admin");
        initParameters.put("loginPassword","1234");//登陆的key是固定的,loginUsername、loginPassword
        //允许谁访问
        initParameters.put("allow","");
        //禁止谁访问
        initParameters.put("moli","192.168.99.123");
        bean.setInitParameters(initParameters);//设置初始化参数
        return bean;
    }
}

测试结果:

再运行一下前面查询数据库的请求/list,刷新发现已经被druid监控:

 

过滤的配置类:

@Bean
public FilterRegistrationBean WebStatFilter(){
    FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
    bean.setFilter(new WebStatFilter());
    Map<String, String> initParameters=new HashMap<>();
    //这些东西不进行统计
    initParameters.put("exclusions","*.js,*.css,/druid/*");
    bean.setInitParameters(initParameters);
    return bean;
}

 
 

3.整合mybatis

首先导入整合包


<dependency>
    <groupId>org.mybatis.spring.bootgroupId>
    <artifactId>mybatis-spring-boot-starterartifactId>
    <version>2.2.2version>
dependency>

连接数据库:

实体类:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String pwd;
}

mapper接口:

@Repository//代表被spring接管
@Mapper//这个注解表示这是一个mybatis的mapper接口
//@MapperScan("com.moli.mapper")用来扫描包,发现mapper接口,用在主类上
public interface UserMapper {
    int add(User user);
    int delete(@Param("id")int id);
    int update(User user);
    List<User> query();
    User queryById(@Param("id") int id);
}

application.yaml配置:

#整合mybatis
mybatis:
  type-aliases-package: com.moli.pojo
  mapper-locations: classpath:mybatis/mapper/*.xml

在resource包下新建mybatis包,再建mapper包—UserMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.moli.mapper.UserMapper">
    <select id="query" resultType="User">
        select * from mybatis.user
    select>
    <select id="queryById" resultType="User">
        select * from mybatis.user where id=#{id}
    select>
    <insert id="add" parameterType="User">
        insert into mybatis.user (id,user.name,pwd) values(#{id},#{name},#{pwd})
    insert>
    <update id="update" parameterType="User">
        update mybatis.user set user.name=#{name},pwd=#{pwd} where id=#{id}
    update>
    <delete id="delete" parameterType="int">
        delete from mybatis.user where id=#{id}
    delete>
mapper>

在controller包中测试

@RestController
public class UserController {
    @Autowired
    UserMapper userMapper;
    
    @RequestMapping("/queryuser")
    public List<User> a(){
        List<User> query = userMapper.query();
        return query;
    }
    @RequestMapping("/queryid/{id}")
    public User byid(@PathVariable int id){
        User user = userMapper.queryById(id);
        return user;
    }
    @RequestMapping("/adduser")
    public int adduser(){
        int add = userMapper.add(new User(2,"哈哈哈","qwdfb"));
        return add;
    }
    @RequestMapping("/updateuser")
    public int updateuser(){
        int update = userMapper.update(new User(7, "嗷嗷嗷", "wjs098987"));
        return update;
    }
    @RequestMapping("/del")
    public int del(){
        int delete = userMapper.delete(9);
        return delete;
    }
}

 
 

4.SpringSecurity 4.1简介

在 Web 开发中,安全一直是非常重要的一个方面。安全虽然属于应用的非功能性需求,但是应该在应用开发的第一天就考虑进来。如果在应用开发的后期才考虑安全的问题,就可能陷入一个两难的境地:一方面,应用存在严重的安全漏洞,无法满足用户的要求,并可能造成用户的隐私数据被攻击者窃取;另一方面,应用的基本架构已经确定,要修复安全漏洞,可能需要对系统的架构做出比较重大的调整,影响应用的发布进程。

Spring Security是一个框架,侧重于为Java应用程序提供身份验证和授权。与所有Spring项目一样,Spring安全性的真正强大之处在于它可以轻松地扩展以满足定制需求。

Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入 spring-boot-starter-security 模块,进行少量的配置,即可实现强大的安全管理!

记住几个类:

  • WebSecurityConfigurerAdapter:自定义Security策略
  • AuthenticationManagerBuilder:自定义认证策略
  • @EnableWebSecurity:开启WebSecurity模式   @EnableXXX开启某个功能

Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制):

“认证”(Authentication)

身份验证,如用户名/用户ID和密码,以验证您的身份。

“授权” (Authorization)

授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。

 

4.2环境搭建

导入静态资源:

导入thymeleaf依赖:

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

并关闭thymeleaf缓存:

spring.thymeleaf.cache=false

编写controller确保页面能够跳转:

@Controller
public class RouterController {
    @RequestMapping({"/" ,"/index"})
    public String toindex(){
        return "index";
    }
    @RequestMapping("/level1/{id}")
    public String l1(@PathVariable int id){
        return "views/level1/"+id;
    }
    @RequestMapping("/level2/{id}")
    public String l2(@PathVariable int id){
        return "views/level2/"+id;
    }
    @RequestMapping("/level3/{id}")
    public String l3(@PathVariable("id") int id){
        return "views/level3/"+id;
    }
    @RequestMapping("/toLogin")
    public String tologin(){
        return "views/login";
    }
}

首页:

 

4.3用户认证和授权

官网:https://spring.io/projects/spring-security

引入启动器:

<dependency>
   <groupId>org.springframework.bootgroupId>
   <artifactId>spring-boot-starter-securityartifactId>
dependency>
//编程思想: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("vip2").
        antMatchers("/level3/**").hasRole("vip3");
        //没有授权会跳转到登陆页面,如下开启了登陆页面
        http.formLogin();
        //开启记住我功能,cookie
        http.rememberMe();
    }

    //认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //这些数据正常从数据库读取,但没有连接数据库就直接从内存(inMemoryAuthentication())读取更快
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
        .withUser("铭").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2")
        .and()
        .withUser("桑").password(new BCryptPasswordEncoder().encode("789")).roles("vip3");
    }
    //报错----There is no PasswordEncoder mapped for the id "null"
    //解决----passwordEncoder(new BCryptPasswordEncoder())对密码进行编码
}
//定制登录页
http.formLogin().loginPage("/toLogin").loginProcessingUrl("/login").usernameParameter("name").passwordParameter("pwd");

//自定义记住我
http.rememberMe().rememberMeParameter("remember");
<div class="field">
    <input type="checkbox"  name="remember"/>记住我
div>

 

4.4注销及权限控制

添加注销按键:

//注销,并调转到首页
http.logout().logoutSuccessUrl("/");
//假如登出报了404页面错误,就添加如下
//关闭csrf功能:跨站请求伪造,默认只能通过post方式提交logout请求.而我们登出是get所以会报404
http.csrf().disable();

 

我们现在又来一个需求:用户没有登录的时候,导航栏上只显示登录按钮,用户登录之后,导航栏可以显示登录的用户信息及注销按钮!还有就是,比如用户,它只有 vip2,vip3功能,那么登录则只显示这两个功能,而vip1的功能菜单不显示!

导入整合包:


<dependency>
    <groupId>org.thymeleaf.extrasgroupId>
    <artifactId>thymeleaf-extras-springsecurity5artifactId>
    <version>3.0.4.RELEASEversion>
dependency>

在index.html中导入命名空间:

xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"

菜单根据用户的动态实现:

测试结果:

 
 
 

5.Shiro 5.1简介

Apache下的Shiro是一个强大且易用的Java安全框架,可以完成身份验证、授权、密码和会话管理。Shiro 不仅可以用在 JavaSE 环境中,也可以用在 JavaEE 环境中。

官网: http://shiro.apache.org/

 

功能:

Authentication:身份认证/登录,验证用户是不是拥有相应的身份;

Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情;

Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;

Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;

Web Support:Web支持,可以非常容易的集成到Web环境;

Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;

Concurrency:shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;

Testing:提供测试支持;

Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;

Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。
 

从外部看:

三大对象:Subject用户、SecurityManager管理所有用户、Realm连接数据

Subject:主体,代表了当前“用户”,应用代码直接交互的对象是Subject,与当前应用交互的任何东西都是Subject,如人,网络爬虫,机器人等是抽象概念;所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者。

SecurityManager:安全管理器,即所有与安全有关的 *** 作都会与SecurityManager交互;且它管理着所有Subject;可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器。

Realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行 *** 作;可以把Realm看成DataSource,即安全数据源。

最简单的一个Shiro应用-----------应用代码通过Subject来进行认证和授权,而Subject又委托给SecurityManager;我们需要给Shiro的SecurityManager注入Realm,从而让SecurityManager能得到合法的用户及其权限进行判断。

 

5.2快速入门

GitHub地址:
https://gitcode.net/mirrors/apache/shiro?utm_source=csdn_github_accelerator

1.建一个maven父工程,删掉不必要的部分scr;创建一个普通的Maven子工程

2.去github中/samples/quickstart里拿到pom.xml、 log4j.properties、shiro.ini、Quickstart.java

<dependencies>
    <dependency>
        <groupId>org.apache.shirogroupId>
        <artifactId>shiro-coreartifactId>
        <version>1.5.3version>
    dependency>
    
    <dependency>
        <groupId>org.slf4jgroupId>
        <artifactId>jcl-over-slf4jartifactId>
        <version>1.7.26version>
    dependency>
    <dependency>
        <groupId>org.slf4jgroupId>
        <artifactId>slf4j-log4j12artifactId>
        <version>1.7.26version>
    dependency>
    <dependency>
        <groupId>log4jgroupId>
        <artifactId>log4jartifactId>
        <version>1.2.17version>
    dependency>
dependencies>
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
[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
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.text.IniRealm;
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;

public class Quickstart {

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

    public static void main(String[] args) {
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
        securityManager.setRealm(iniRealm);
        SecurityUtils.setSecurityManager(securityManager);

        //获得当前对象subject
        Subject currentUser = SecurityUtils.getSubject();
        //通过当前对象拿到session
        Session session = currentUser.getSession();
        session.setAttribute("someKey", "aValue");
        String value = (String) session.getAttribute("someKey");
        if (value.equals("aValue")) {
            log.info("Retrieved the correct value! [" + value + "]");
        }

        // 判断当前用户是否被认证
        if (!currentUser.isAuthenticated()) {
            //Token令牌
            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 (AuthenticationException ae) {
                //unexpected condition?  error?
            }
        }

        //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);
    }
}

 

5.3spring boot中集成

1.先导入thyme leaf依赖和shiro整合springbooot的包

<dependency>
    <groupId>org.thymeleafgroupId>
    <artifactId>thymeleaf-spring5artifactId>
dependency>
<dependency>
    <groupId>org.thymeleaf.extrasgroupId>
    <artifactId>thymeleaf-extras-java8timeartifactId>
dependency>
<dependency>
    <groupId>org.apache.shirogroupId>
    <artifactId>shiro-springartifactId>
    <version>1.8.0version>
dependency>

2.编写配置类

@Configuration
public class ShiroConfig {
    
    //3.shiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("security") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);
        return bean;
    }
    
    //2.DefaultWebSecurityManager
    @Bean(name = "security")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联Realm对象
        securityManager.setRealm(userRealm);
        return securityManager;
    }
    
    //1.创建Realm对象,需要自定义类
    @Bean
    public UserRealm userRealm(){
        return new UserRealm();
    }
}

3.UserRealm类

public class UserRealm extends AuthorizingRealm {
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("doGetAuthorizationInfo");
        return null;
    }
    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("doGetAuthenticationInfo");
        return null;
    }
}

 

5.4登录拦截

1.四个页面:index.html、add.html、update.html、login.html


<p th:text="${msg}">p>
<a th:href="@{/add}">adda>  |  <a th:href="@{/update}">updatea>

<h1>登录h1>
<hr>
<form action="">
    <p>用户名:<input type="text" name="name">p>
    <p>密码:<input type="text" name="password">p>
    <p>提交<input type="submit" name="submit">p>
form>

2.controller

@Controller
public class testcontroller {
    @RequestMapping({"/","/index"})
    public String index(Model model){
        model.addAttribute("msg","hello");
        return "index";
    }
    @RequestMapping("/add")
    public String add(){
        return "user/add";
    }
    @RequestMapping("/update")
    public String update(){
        return "user/update";
    }
    @RequestMapping("/tologin")
    public String login(){
        return "login";
    }
}

3.在ShiroConfig中的getShiroFilterFactoryBean方法中添加如下配置:

  • anon: 无需认证就可以访问
  • authc: 必须认证了才能访问
  • user: 必须拥有 记住我 功能才能用
  • perms: 拥有对某个资源的权限才能访问
  • role: 拥有某个角色权限
//需要认证了才能够访问
LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/add","authc");
filterChainDefinitionMap.put("/update","authc");
bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
//没认证就跳转到登陆页面
bean.setLoginUrl("/tologin");

 

5.5用户认证

1.在Controller中编写用户提交表单之后处理

@RequestMapping("/loginafter")
public String loginafter(String name,String password,Model model){
    //获取一个用户
    Subject subject = SecurityUtils.getSubject();
    //封装用户数据
    UsernamePasswordToken token = new UsernamePasswordToken(name, password);
    try{
        subject.login(token);//登录
        return "index";
    }catch (UnknownAccountException e){
        model.addAttribute("msg","用户名不存在");
        return "login";
    }catch (IncorrectCredentialsException e){
        model.addAttribute("msg","密码不正确");
        return "login";
    }catch (LockedAccountException e){
        model.addAttribute("msg","用户被锁");
        return "login";
    }
}

2.login.html的修改

3.用户认证编写UserRealm中的认证(doGetAuthenticationInfo)

@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    //用户名,密码---伪造数据库
    String name ="root";
    String password="1234";
    //用户名认证
    UsernamePasswordToken userToken = (UsernamePasswordToken)authenticationToken;
    if (!userToken.getUsername().equals(name)){
        return null;//抛出异常
    }
    //密码认证shiro做,防止密码泄露
    //也可以用md5加密,md5盐值加密
    return new SimpleAuthenticationInfo("",password,"");
}

测试结果:

 

5.6整合mybatis

1.导入依赖:

<dependency>
    <groupId>mysqlgroupId>
    <artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>druidartifactId>
    <version>1.2.8version>
dependency>
<dependency>
    <groupId>org.mybatis.spring.bootgroupId>
    <artifactId>mybatis-spring-boot-starterartifactId>
    <version>2.2.2version>
dependency>

2.连接数据库,并配置配置文件(详情参考本文章第3小块—整合mybatis)

3.实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String pwd;
}

4.mapper接口

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

5.resource里的UserrMapper.xml

<mapper namespace="com.moli.mapper.UserMapper">
    <select id="queryByName" parameterType="String" resultType="User">
        select * from mybatis.user where user.name=#{name}
    select>
mapper>

6.service

public interface UserService {
    public User queryByName(String name);
}
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    UserrMapper userrMapper;
    @Override
    public User queryByName(String name) {
        return userrMapper.queryByName(name);
    }
}

7.测试

@SpringBootTest
class Springboot08Shiro1ApplicationTests {
    @Autowired
    UserServiceImpl userService;
    @Test
    void contextLoads() {
        System.out.println(userService.queryByName("嘿嘿嘿"));
    }
}

8.修改UserRealm

 

5.7授权

1.config

2.controller增加视图跳转

@RequestMapping("/noauth")
@ResponseBody
public String Unauthorized(){
    return "未授权";
}

3.UserRealm:

@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    info.addStringPermission("add");
    return info;
}

任何一个数据库的用户都可以访问add:

4.数据库增加一个perms字段,并修改对应的实体类,增加权限后,只有有权限的用户才能访问add、update

@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    //info.addStringPermission("add");
    //获取当前对象
    Subject subject = SecurityUtils.getSubject();
    User currentUser = (User)subject.getPrincipal();//获取user
    info.addStringPermission(currentUser.getPerms());
    return info;
}

 

5.8thymeleaf

1.导入thymeleaf


<dependency>
    <groupId>com.github.theborakompanionigroupId>
    <artifactId>thymeleaf-extras-shiroartifactId>
    <version>2.0.0version>
dependency>

引入thymeleaf是为了让有add权限的,只能看到add链接。

需要配置一下在shiroConfig中:

//thymeleaf
@Bean
public ShiroDialect shiroDialect(){
    return new ShiroDialect();
}

2.得到session

3.index.html

<h1>首页h1>
<p th:text="${msg}">p>

<div th:if="${session.loginuser==null}">
    <a th:href="@{/tologin}">登陆a>
div>
<hr>
<div shiro:hasPermission="add">
    <a th:href="@{/add}">adda>
div>
<div shiro:hasPermission="update">
    <a th:href="@{/update}">updatea>
div>

测试结果:


 

 
 

6.写一个网站思路
  • 模板:别人写好的我们加以改进
  • 框架:组件自己动手拼接,bootstrap、Layui、semantic-ui、x-admin

步骤:

  1. 前端首先确定页面长什么样子,需要什么数据
  2. 设计数据库
  3. 前端能够独立运行
  4. 数据接口如何对接
  5. 前后端联调测试

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/720427.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-25
下一篇 2022-04-25

发表评论

登录后才能评论

评论列表(0条)

保存