SpringBoot 企业级简化开发(四)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: SpringBoot 企业级简化开发

SpringBoot 企业级简化开发(三)https://developer.aliyun.com/article/1469562


配置druid步骤

  1. 导入相关依赖,
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.6</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>


  1. 配置对应的数据源
  1. 对应配置文件
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    password: xxx
    username: xxx
    url: jdbc:mysql://localhost:3306/mybatis #?serverTimezone=UTC&useUnicode=true&charcterEncoding=UTF-8
    type: com.alibaba.druid.pool.DruidDataSource


  1. 去将我们的增删改查方法测试一下就好了,用的是jdbc模版,由boot提供:jdbcTemplate
package com.hyc.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
@RestController
public class Datacontroller {
    @Autowired
    JdbcTemplate jdbcTemplate;
    @RequestMapping("/userlist")
    public List<Map<String,Object>> userlist(){
        String sql = "select * from mybatis.user";
        List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
        return  maps;
    }
    
    @RequestMapping("/addUser")
    public String addUser(){
        String sql = "insert into mybatis.user(id,name,pwd) values(1,'小胡','123456')";
        jdbcTemplate.update(sql);
        return "insert";
    }
    
    @RequestMapping("/upddateUser/{id}")
    public String upddateUser(@PathVariable("id") int id){
        String sql = "update mybatis.user set name=?,pwd=?  where id ="+id;
        Object[] obj = new Object[2];
        obj[0] = "小明";
        obj[1] = "66666";
        jdbcTemplate.update(sql,obj);
        return "update";
    }
    
    @RequestMapping("/DeleteUser/{id}")
    public String DeleteUser(@PathVariable("id") int id){
        String sql = "delete from mybatis.user where id=? ";
        jdbcTemplate.update(sql,id);
        return "DeleteUser";
    }
}


  1. YML配置druid常用的一些配置
#SpringBoot默认是不注入这些的,需要自己绑定
    #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.Properity
    #则导入log4j 依赖就行
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500


  1. 配置sql监控,和过滤请求:这里注意不要私自改动:loginusername等key
package com.hyc.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
import javax.servlet.ServletRegistration;
import javax.sql.DataSource;
import java.util.HashMap;
@Configuration
public class DruidConfing {
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource druidDataSource(){
        return new DruidDataSource();
    }
    //后台监控
    @Bean
    public ServletRegistrationBean ServletRegistrationBean(){
        ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
        HashMap<String, String> InitParameters = new HashMap<>();
        InitParameters.put("loginUsername","admin");
        InitParameters.put("loginPassword","123456");
        InitParameters.put("allow","");
        //后台监控
        bean.setInitParameters(InitParameters);
        return  bean;
    }
    @Bean
    public FilterRegistrationBean filterRegistrationBean(){
        FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
        //可以过滤那些请求?
        bean.setFilter(new WebStatFilter());
        bean.addUrlPatterns("/*");
        bean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        return bean;
    }
}


SpringBoot整合mybatis

准备工作,

寻找依赖,添加,这是个第三方的启动器

<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>

去创建使用mybatis的需要文件,

实体类:user

mapper接口:usermapper

配置文件:usermapper.xml

创建完毕后我们去boot的配置文件配置mybatis:

#mybatis配置
mybatis.mapper-location=classpath:mapper/*.xml
mybatis.type-aliases-package=com.hyc.pojo

配置文件模板:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace 写入 自己 dao 里的接口名称-->
<mapper namespace="com.hyc.mapper.userMapper">
</mapper>

用mybatis的注解来 映射,实体类:

package com.hyc.mapper;
import com.hyc.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface userMapper {
    List<User> getuser();
    User getuserByid(int id);
    int addUser(User user);
    int UpdUser(User user);
    int DelUser(int id);
}

之后编写映射文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace 写入 自己 dao 里的接口名称-->
<mapper namespace="com.hyc.mapper.userMapper">
    <insert id="addUser">
        insert into mybatis.user(id, name, pwd) VALUES (#{id},#{name},#{pwd});
    </insert>
    <update id="UpdUser">
        update mybatis.user
        set user.name = #{name},user.pwd =#{pwd}
        where id = #{id};
    </update>
    <delete id="DelUser">
        delete from  mybatis.user where id=#{id}
    </delete>
    <select id="getuser" resultType="com.hyc.pojo.User">
        select * from mybatis.user
    </select>
    <select id="getuserByid" resultType="com.hyc.pojo.User">
        select *
        from mybatis.user where id=#{id};
    </select>
</mapper>

编写控制层测试即可:

@RestController
public class usercontroller {
    @Autowired
    private userMapper userMapper;
    @RequestMapping("/queryList")
    public List<User> queryList(){
        List<User> getuser = userMapper.getuser();
        for (User user : getuser) {
            System.out.println(user);
        }
        return getuser;
    }
}

SpringSecurity(安全)

Springsecurity简介

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

web开发中 ,安全是第一位的,我们学过的有,过滤器,拦截器

spring security 的核心功能主要包括:

  • 认证 (你是谁)
  • 授权 (你能干什么)
  • 攻击防护 (防止伪造身份)

功能性需求:否

做网站需要考虑什么?

  1. 漏洞,隐私泄露问题
  2. 架构一旦确定,再加入安全十分浪费人力,

目前两大火热的安全框架:SpringSecurity和shrio,他们两个十分相似

  • 功能权限
  • 访问权限
  • 菜单权限
  • 以前我们都是用拦截器,过滤器,来做,这样会有一个缺点,大量的原生代码,冗余

其核心就是一组过滤器链,项目启动后将会自动配置。最核心的就是 Basic Authentication Filter 用来认证用户的身份,一个在spring security中一种过滤器处理一种认证方式。

记住几个类:

  • webSecurityConfigurerAdapter:自定义security策略
  • AuthenticationManagerBuilder:自定义认证策略
  • @EnablewebSecurity:开启webSercurity

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

帮助文档:https://docs.spring.io/spring-security/site/docs/current/reference/html5/

Security实战

导入相关依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

一般我们,配置Security的配置类都有一个模式

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
    }
}

接下来就可以来制定我们的需求了

需求1:首页所有人可以访问,功能页只有对应的权限才能进去

编写:SecurityConfig 类

@Override
    protected void configure(HttpSecurity http) throws Exception {
        //首页所有人可以访问,功能页只有对应的权限才能进去
        http.authorizeRequests()//授权请求方法
                .antMatchers("/").permitAll()
                .antMatchers("views/level1/*").hasRole("vip1")//什么角色可以访问什么位置
                .antMatchers("views/level2/*").hasRole("vip2")
                .antMatchers("views/level3/*").hasRole("vip3");
    }

给不同的用户,添加访问权限,

PS:在5.x之后密码要加密才可以有效: 使用以这个为后缀的类passwordEncoder

//密码编码:passwordencoder
    //5.x之后更新了很多的加密方法
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("hyc").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
                .and()
                .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
                .and()
                .withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");
    }

设置注销:

http.logout().logoutSuccessUrl("/index");

thymeleaf 常用命名空间:

xmlns:th=http://www.thymeleaf.org
xmlns:sec=http://www.thymeleaf.org/extras/spring-security
xmlns:shiro=http://www.pollix.at/thymeleaf/shiro
html lang=en xmlns:th=http://www.thymeleaf.org 
        xmlns:sec=http://www.thymeleaf.org/extras/spring-security
        xmlns:shiro=http://www.pollix.at/thymeleaf/shiro

常用的内容:

PS:如果403:csrf().disable();关闭跨站攻击安全

匹配的路径不需要认证:.antMatchers("/","/test/hello","/user/login").permitAll()

按照权限显示:sec:authorize="hasRole("xxx")

是否登陆显示:sec:authorize="!isAuthenticated()"

指定登陆的页面:.loginPage("/toLogin")

登陆访问路径:提交表单之后跳转的地址,可以看作一个中转站,这个步骤就是验证user的一个过程:.loginProcessingUrl("/login");

注销之后转发的页面:.logoutSuccessUrl("/index");

记住我:

//开启记住我功能 cookie 默认保存两周
        http.rememberMe();

自定义用户参数和密码参数

//.usernameParameter()
//.passwordParameter()

shiro(安全)

阿帕奇的安全框架

Apache Shiro是一个Java的安全管理框架,可以用在JavaEE环境下,也可以用在JavaSE环境下。

此前我们学习了很多有关阿帕奇的东西:maven,tomcat,等等

官方号称十分钟就可以入门,

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

为什么学他?:

(1)spring security 功能完善,学习成本偏高;
(2)shiro 学习成本低,简单的安全框架,基本功能存在(登录认证,权限认证); 
(3)spring mvc interceptor(拦截器) 只能做登录认证,不能做权限认证。

他能做什么?

Authentication:身份认证/登录;

Authorization:授权;

Session Manager:会话管理;

Cryptography:加密;

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

Caching:缓存;

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

Testing:提供测试支持;

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

Remember Me:记住我。

Shiro不会去维护用户、维护权限;这些需要我们自己去设计/提供;然后通过相应的接口注入给Shiro。

shiro架构

Subject:主体;

SecurityManager:相当于SpringMVC中的DispatcherServlet或者Struts2中的FilterDispatcher;它管理着所有Subject、且负责进行认证和授权、及会话、缓存的管理。

Authenticator:认证器;

Authrizer:授权器,;

Realm:可以有1个或多个Realm,是安全实体数据源;可以是JDBC实现,也可以是LDAP实现,或者内存实现等等;

SessionManager:**Shiro自己的Session来管理主体与应用之间交互的数据;

SessionDAO:**DAO大家都用过,数据访问对象,用于会话的CRUD;同时SessionDao也可以使用Cache进行缓存以提高性能。

CacheManager:缓存控制器,管理如用户、角色、权限等的缓存

Cryptography:密码模块

helloshiro

导入相关依赖:官方依赖

<dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.6.0</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <version>1.7.21</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.21</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
<resources>
                <resource>
                    <directory>${basedir}/src/main/webapp</directory>
                </resource>
                <resource>
                    <directory>${basedir}/src/main/resources</directory>
                </resource>
                <resource>
                    <directory>${basedir}/src/main/java</directory>
                    <includes>
                        <include>**/*.xml</include>
                        <include>**/*.properties</include>
                        <include>**/*.yml</include>
                    </includes>
                </resource>
            </resources>

修改后的Quickstart类,

最新版本建议将:

FactorySecurityManager factory = new IniSecurityManagerFactory(classpath:shiro.ini);
SecurityManager securityManager = factory.getInstance();
转换位下面这样
DefaultSecurityManager securityManager = new DefaultSecurityManager();
IniRealm iniRealm = new IniRealm(classpath:shiro.ini);
securityManager.setRealm(iniRealm);

下面代码是Quickstart类:

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
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):
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
        securityManager.setRealm(iniRealm);
        // 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 currentUser = SecurityUtils.getSubject();
        // Do some stuff with a Session (no need for a web or EJB container!!!)
        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 + "]");
        }
        // let's login the current user so we can check against roles and permissions:
        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);
    }
}

三大对象:

  1. Subject
  2. SecurityManage
  3. fealm

shiro整个流程

常用过滤器如下

  • anon:无需认证访问
  • authc:必须认证了才能访问
  • user:记住我开启了,才可以用
  • perms:拥有对某个资源的权限才能访问
  • role:该资源必须得到角色权限才可以访问

代码实战:

首先是shiroconfig,我们从下往上配置:

  1. 首先是创建一个realm类
  2. 之后是创建shiroconfig
  3. 之后从下往上配置
  1. 首先是引入realm类
  2. 配置安全管理器
  3. 之后设置过滤工厂
package com.hyc.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.LinkedList;
import java.util.Map;
@Configuration
public class shrioconfig {
//    shirofilterfactoryBean
     @Bean
        public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            //设置安全管理器
            bean.setSecurityManager(defaultWebSecurityManager);
            /*
            * 常用过滤器如下
            * anon:无需认证访问
            * authc:必须认证了才能访问
            * user:记住我开启了,才可以用
            * perms:拥有对某个资源的权限才能访问
            * */
            * */
         Map<String,String> filter = new LinkedHashMap();
         filter.put("/add","anon");
         filter.put("/upd","authc");
         bean.setFilterChainDefinitionMap(filter);
         bean.setLoginUrl("/tologin"); 
         return bean;
        }
//    dafultwebSecurityManager
    @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();
    }
}

realm对象需要引用外面的类 userrealm,我们需要继承AuthorizingRealm来获得授权,认证方法

package com.hyc.config;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
public class userrealm extends AuthorizingRealm {
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("授权=========>");
        return null;
    }
    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("认证=========>");
        return null;
    }
}

用户认证:

我们需要去编写config类,设置权限,什么路径需要什么权限,

@Bean
        public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            //设置安全管理器
            bean.setSecurityManager(defaultWebSecurityManager);
            /*
            * 常用过滤器如下
            * anon:无需认证访问
            * authc:必须认证了才能访问
            * user:记住我开启了,才可以用
            * perms:拥有对某个资源的权限才能访问
            role:该资源必须得到角色权限才可以访问
            * */
         Map<String,String> filter = new LinkedHashMap();
         filter.put("/user/add","perms[user:add]");
         filter.put("/user/upd","perms[user:upd]");
         bean.setFilterChainDefinitionMap(filter);
         bean.setLoginUrl("/tologin");
         bean.setUnauthorizedUrl("/unauth");
         return bean;
        }

之后去realm去认证,认证的信息是我们从数据库user表中查询出来的数据

//认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("认证=========>");
//        获取当前的用户
        Subject subject = SecurityUtils.getSubject();
//        封装用户数据
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        user user = userService.queryUserByName(token.getUsername());
        if (user==null){
            return null;
        }
        //认证的时候创建用户登陆的session
        Session session = subject.getSession();
                //将用户的属性传入到session中
        session.setAttribute("loginUser",user);
    //如何让我们的user可以全局使用,我们需要设置info中第一个参数为user
        return new SimpleAuthenticationInfo(user,user.getPassword() ,"");
    }

之后再认证之后获取用户对象授权,什么对象可以访问什么页面

//授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("授权=========>");
        //授权信息
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //传递用户信息
        Subject subject = SecurityUtils.getSubject();
        user currentUser = (user) subject.getPrincipal();
        //从数据库中获取授权角色
        info.addStringPermission(currentUser.getParms());
        info.addRole("user:add");
        info.addRole("user:upd");
        return info;
    }

登陆功能

controller

@RequestMapping("/login")
    public String login(String username,String password,Model model){
        //获取角色对象
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
        try {
            subject.login(token);//判断令牌是否正确
            return "index";
        } catch (UnknownAccountException uae) {//用户名不存在
            model.addAttribute("msg","用户名不存在");
            return "login";
        } catch (IncorrectCredentialsException ice) {//密码不存在
            model.addAttribute("msg","密码错误");
            return "login";
        }
    }

这里有一个拓展可以做:就是密码加密处理

我们这里调用的login()方法会走上面我们配置的一系列流程

整合shiro和thymeleaf

需要的命名空间

xmlns:th="http://www.thymeleaf.org"
xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro"

要使用整合我们还需要导入整合包依赖

<!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro -->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

之后需要去配置类配置一个新的bean

//整合ShiroDialect:用来整合shiro thymeleaf
    @Bean
    public ShiroDialect getshiroDialect(){
        return new ShiroDialect();
    }

完成以上步骤就可以在模版引擎上使用shiro了

前端页面内容

<!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>
<span th:text="${msg}"></span>
<!--从session中判断值-->
<div th:if="${session.get('loginUser')==null}">
    <a th:href="@{/tologin}">登录</a>
</div>
<a th:href="@{/logout}">注销</a>
<p th:text="${msg}"></p>
<hr>
    <!--通过shiro中的hasPermission方法,判断登录的用户是否有这个权限,有权限才显示-->
<div shiro:hasPermission="user:add">
    <a th:href="@{/user/add}" >add</a>
</div>
<div shiro:hasPermission="user:upd">
    <a th:href="@{/user/upd}">update</a>
</div>
</body>
</html>

源码

配置相关

shiroconfig

package com.hyc.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
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.LinkedList;
import java.util.Map;
@Configuration
public class shrioconfig {
//    shirofilterfactoryBean
     @Bean
        public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            //设置安全管理器
            bean.setSecurityManager(defaultWebSecurityManager);
            /*
            * 常用过滤器如下
            * anon:无需认证访问
            * authc:必须认证了才能访问
            * user:记住我开启了,才可以用
            * perms:拥有对某个资源的权限才能访问
            * */
         Map<String,String> filter = new LinkedHashMap();
         filter.put("/user/add","perms[user:add]");
         filter.put("/user/upd","perms[user:upd]");
         bean.setFilterChainDefinitionMap(filter);
         bean.setLoginUrl("/tologin");
         bean.setUnauthorizedUrl("/unauth");
         return bean;
        }
//    dafultwebSecurityManager
    @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();
    }
    //整合ShiroDialect:用来整合shiro thymeleaf
    @Bean
    public ShiroDialect getshiroDialect(){
        return new ShiroDialect();
    }
}

userrealm

package com.hyc.config;
import com.hyc.pojo.user;
import com.hyc.service.userServiceImpl;
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.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
public class userrealm extends AuthorizingRealm {
    @Autowired
    userServiceImpl userService;
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("授权=========>");
        //授权信息
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //传递用户信息
        Subject subject = SecurityUtils.getSubject();
        user currentUser = (user) subject.getPrincipal();
        //授权角色
        info.addStringPermission(currentUser.getParms());
        info.addRole("user:add");
        info.addRole("user:upd");
        return info;
    }
    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("认证=========>");
//        获取当前的用户
        Subject subject = SecurityUtils.getSubject();
//        封装用户数据
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        user user = userService.queryUserByName(token.getUsername());
        if (user==null){
            return null;
        }
        Session session = subject.getSession();
        session.setAttribute("loginUser",user);
        return new SimpleAuthenticationInfo(user,user.getPassword() ,"");
    }
}

控制层

package com.hyc.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.session.ProxiedSession;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@Controller
public class Mycontroller {
    @RequestMapping({"/","/index"})
    public String toIndex(Model model){
        model.addAttribute("msg","hello");
        return "index";
    }
    @RequestMapping("/user/add")
    public String add(){
        return "user/add";
    }
    @RequestMapping("/user/upd")
    public String upd(){
        return "user/upd";
    }
    @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);
        try {
            subject.login(token);
            return "index";
        } catch (UnknownAccountException uae) {//用户名不存在
            model.addAttribute("msg","用户名不存在");
            return "login";
        } catch (IncorrectCredentialsException ice) {//密码不存在
            model.addAttribute("msg","密码错误");
            return "login";
        }
    }
    @ResponseBody
    @RequestMapping("/unauth")
    public String unauth(){
        return "您没有权限";
    }
    @RequestMapping("/logout")
    public String logout(){
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        session.removeAttribute("loginUser");
        return "index";
    }
}

前端页面:

index

<!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>
<span th:text="${msg}"></span>
<!--从session中判断值-->
<div th:if="${session.get('loginUser')==null}">
    <a th:href="@{/tologin}">登录</a>
</div>
<a th:href="@{/logout}">注销</a>
<p th:text="${msg}"></p>
<hr>
<div shiro:hasPermission="user:add">
    <a th:href="@{/user/add}" >add</a>
</div>
<div shiro:hasPermission="user:upd">
    <a th:href="@{/user/upd}">update</a>
</div>
</body>
</html>

login

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


SpringBoot 企业级简化开发(五)https://developer.aliyun.com/article/1469564

目录
相关文章
|
7天前
|
XML Java 数据格式
SpringBoot入门(8) - 开发中还有哪些常用注解
SpringBoot入门(8) - 开发中还有哪些常用注解
24 0
|
1月前
|
前端开发 Java
表白墙/留言墙 —— 初级SpringBoot项目,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
文章通过一个表白墙/留言墙的初级SpringBoot项目实例,详细讲解了如何进行前后端开发,包括定义前后端交互接口、创建SpringBoot项目、编写前端页面、后端代码逻辑及实体类封装的全过程。
74 3
表白墙/留言墙 —— 初级SpringBoot项目,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
|
1月前
|
前端开发 Java 数据安全/隐私保护
用户登录前后端开发(一个简单完整的小项目)——SpringBoot与session验证(带前后端源码)全方位全流程超详细教程
文章通过一个简单的SpringBoot项目,详细介绍了前后端如何实现用户登录功能,包括前端登录页面的创建、后端登录逻辑的处理、使用session验证用户身份以及获取已登录用户信息的方法。
170 2
用户登录前后端开发(一个简单完整的小项目)——SpringBoot与session验证(带前后端源码)全方位全流程超详细教程
|
2月前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的医院门诊预约挂号系统
基于Java+Springboot+Vue开发的医院门诊预约挂号系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的门诊预约挂号管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
136 2
基于Java+Springboot+Vue开发的医院门诊预约挂号系统
|
1月前
|
NoSQL Java Redis
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
这篇文章介绍了如何使用Spring Boot整合Apache Shiro框架进行后端开发,包括认证和授权流程,并使用Redis存储Token以及MD5加密用户密码。
26 0
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
|
18天前
|
JavaScript 前端开发 Java
SpringBoot_web开发-webjars&静态资源映射规则
https://www.91chuli.com/ 举例:jquery前端框架
15 0
|
1月前
|
前端开发 Java 数据库连接
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
本文是一份全面的表白墙/留言墙项目教程,使用SpringBoot + MyBatis技术栈和MySQL数据库开发,涵盖了项目前后端开发、数据库配置、代码实现和运行的详细步骤。
42 0
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
|
1月前
|
开发框架 Java API
「SpringBrick快速入门指南」:一款基于Spring Boot的高级插件化开发框架
「SpringBrick快速入门指南」:一款基于Spring Boot的高级插件化开发框架
52 0
|
1月前
|
机器学习/深度学习 移动开发 自然语言处理
基于人工智能技术的智能导诊系统源码,SpringBoot作为后端服务的框架,提供快速开发,自动配置和生产级特性
当身体不适却不知该挂哪个科室时,智能导诊系统应运而生。患者只需选择不适部位和症状,系统即可迅速推荐正确科室,避免排错队浪费时间。该系统基于SpringBoot、Redis、MyBatis Plus等技术架构,支持多渠道接入,具备自然语言理解和多输入方式,确保高效精准的导诊体验。无论是线上医疗平台还是大型医院,智能导诊系统均能有效优化就诊流程。
|
1月前
|
JavaScript 前端开发 数据可视化
【SpringBoot+Vue项目实战开发】2020实时更新。。。。。。
【SpringBoot+Vue项目实战开发】2020实时更新。。。。。。
47 0