SpingSecurity(三)------根据数据库认证授权

测试环境

IDEA 2020.1.2 

navicat

一:  编写数据库

        需要的表分别为:

 用户表        角色表        用户与角色之间的关系表        菜单表        角色和菜单之间的关系表

        1. 用户表

id 账号 密码 电话 性别 头像 身份证号

       

         2. 角色表

id 角色名(可修改) 角色状态(不可修改)


           

        3. 用户角色关系表

用户的id 角色的id

        4. 菜单表

id 菜单名 图标 父菜单idnull按钮  编码

         5. 菜单与用户的关系表 

用户id 菜单id

二. 创建项目 加依赖 与 核心配置

        1.创建项目

略...

        2.加pom依赖

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.7.17</version>
</parent>
<dependencies>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
  </dependency>
  <!--      web项目  -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <!--  #因为我们引入的springboot依赖是2.7.17的,所有这里是不需要写版本号
           #默认版本是我们 springboot依赖是2.7.17的版本 -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <!--   热部署   -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
  </dependency>
  <!--   支持跳转jsp页面的jar包   -->
  <dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <version>9.0.82</version>
  </dependency>
  <dependency>
    <groupId>org.glassfish.web</groupId>
    <artifactId>javax.servlet.jsp.jstl</artifactId>
    <version>1.2.2</version>
  </dependency>
  <!--   mybatis包   连接数据库 -->
  <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.3</version>
  </dependency>
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.44</version>
  </dependency>
  <!--  分页插件  -->
  <dependency>
    <groupId>com.github.pagehelper </groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.4.3</version>
  </dependency>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>3.8.1</version>
    <scope>test</scope>
  </dependency>
  <!--   加jar  就代表项目加上了安全框架  没有加这个jar就代表项目没有使用安全框架  -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
  </dependency>
  <!--    加test测试依赖    -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
  </dependency>
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
  </dependency>
</dependencies>

        3.核心配置application.yml文件

如果项目启动报错 有可能是这个核心文件的中文注释的原因 删掉就好

spring:
  datasource: # 连接数据库  四大金刚 驱动 url 用户名 密码
    url: jdbc:mysql://localhost:3306/springboottest?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
    password: 123456
    username: root
    driver-class-name: com.mysql.jdbc.Driver
mybatis:   # mybatis
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath:mapper/*.xml #配置扫描mapper.xml文件的位置

三. 编写代码 

        1. 创建config层

                这一层相对于我发布的SpringSecurity(二) 没做任何改变, 这一层写好一次之后在学习前后端分离前使用的时候几乎不用做改变

package com.dys.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import javax.annotation.Resource;

// 配置类
@Configuration // spring框架中的注解   当前的类是一个配置类
@EnableWebSecurity
public class MySecurityConfig  extends WebSecurityConfigurerAdapter {
    /**
     *     从数据库查询需要注入的类  当前项目只有UserServiceImpl实现了userDetailsService
     *     所以理所当然注入的是当前项目只有UserServiceImpl实现了userDetailsService
      */
    @Resource
    private UserDetailsService userDetailsService;



    /**
     * 配置用户的信息
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 不能使用明文密码
        // 配置使用的密码是什么
        PasswordEncoder passwordEncoder = getPasswordEncoder();
        // 通过userDetailsService从数据库查询用户信息  .passwordEncoder(passwordEncoder)配置密码不能是明文的解析器
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);

    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.formLogin()
                .loginPage("/login.html").permitAll()// 登录的页面是login.html
                .defaultSuccessUrl("/home.html") // 访问输入login.html 成功之后默认跳转的页面
                .failureUrl("/fail.html") // 访问失败的跳转页面
                .usernameParameter("uname") // 默认的name值为username 改为自己想改的 在login.html页面
                .passwordParameter("pwd")   //默认的password值为password 改为自己想改的 在login.html页面
                .loginProcessingUrl("/mylogin").permitAll()

        ;
        // 配置一下退出 ---- 退出按钮在home.html中  退回到login.html页面
        http.logout().logoutSuccessUrl("/login.html");

        /**
         *  设置授权 除了这里设置的用户名 其他的一律不可通过 hasRole 这里不需要写Role_框架下会自动加 hasRole只能设置一个用户名
         *  访问时输入的账号为UserServiceImpl中 if判断判断的""中的内容 如果这个账号有下方设置的权限则成功 没有则跳转403页面
         */
        //http.authorizeRequests().antMatchers("/test").hasRole("ADMIN1");
        // 与上面相同 可以设置多个用户名 主要满足其中一个即可
        http.authorizeRequests().antMatchers("/test").hasAnyRole("ADMIN1","ADMIN");
        // 根据菜单判断 逻辑跟上方用户名相同 都是如果能判断到就成功 不能就 403
        //http.authorizeRequests().antMatchers("/test").hasAuthority("menu");

        // 没有权限时登录报错403 配置403页面 设置页面 403.html
        http.exceptionHandling().accessDeniedPage("/403.html");

        // 除了放行之外的其他的路径全部需要认证
        http.authorizeRequests().anyRequest().authenticated();
        // 由于我们设置的 登录是一个html页面
        http.csrf().disable();

    }



    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
    }


    // 用于加密密码

    @Bean
    /**
     * @Bean 与 @Compponent 有什么不同
     * @Compponent 放在类上使用
     * @Bean 可以放在方法上使用
     */
    public PasswordEncoder getPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

   2. 创建mapper层查询 

        查询需要通过实体类进行键值对来查 所以一个查询对应一个实体类

        实体类均用的 lombok 插件

        1. 根据账号查询用户

          实体类

package com.dys.entity;

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

@Data
@AllArgsConstructor
@NoArgsConstructor
public class TabUser {
    private Integer id;
    private String  username;
    private String  password;
    private String  tel;
    private String  sex;
    private String  imgpath;
    private String  idcard;
}

        查询

package com.dys.mapper;

import com.dys.entity.TabUser;
import org.apache.ibatis.annotations.Select;

public interface UserMapper {
    @Select("select * from tab_user where username=#{username}")
    TabUser MyuserName(String username);
}

             2. 根据用户的id查询该用户有哪些角色

             实体类

package com.dys.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.FieldNameConstants;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class TabRole {
    private Integer id;
    private String rname;
    private String rcode;
}

        查询 

package com.dys.mapper;

import com.dys.entity.TabRole;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface RoleMapper {
    @Select("select * from tab_role r,tab_user_role ur where r.id = ur.rid and ur.uid=#{uid}")
    List<TabRole> findByUid(Integer uid);
}

  

        3. 根据用户角色的id查询各个角色的菜单

           一个用户可以有多个角色 所以想要查每个角色的菜单需要接收多个id 这个相对于上面两个查询这里需要在resources里面创建.xml文件编写sql语句 

        实体类

package com.dys.entity;

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

@Data
@AllArgsConstructor
@NoArgsConstructor
public class TabMenu {
    private Integer id;
    private String mname;
    private String icon;
    private Integer pid;
    private String mcode;
}

        mapper接口

package com.dys.mapper;

import com.dys.entity.TabMenu;

import java.util.List;

public interface MenuMapper {
    List<TabMenu> findByRoleIds(List<Integer> id);
}

       MenuMapper.xml文件

<?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">

<mapper namespace="com.dys.mapper.MenuMapper">
    <select id="findByRoleIds" resultType="com.dys.entity.TabMenu">
        select DISTINCT m.* from tab_menu m,tab_role_menu rm
        where m.id=rm.mid and rm.rid in(
        <foreach collection="list" item="i" separator=",">
            #{i}
        </foreach>
        )
    </select>
</mapper>

 

        3. 创建service层进行使用

package com.dys.service;

import com.dys.entity.TabMenu;
import com.dys.entity.TabRole;
import com.dys.entity.TabUser;
import com.dys.mapper.MenuMapper;
import com.dys.mapper.RoleMapper;
import com.dys.mapper.UserMapper;
import lombok.SneakyThrows;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.nio.file.attribute.UserPrincipalNotFoundException;
import java.util.ArrayList;
import java.util.List;

@Service
public class MyUserService implements UserDetailsService {
    @Resource
    private UserMapper userMapper;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private MenuMapper menuMapper;
    @SneakyThrows
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 根据username 查询数据库中用户是否存在
        TabUser tabUsers = userMapper.MyuserName(username);
        if (tabUsers == null){
            // 如果查不到用户抛一个异常
            throw new UserPrincipalNotFoundException("用户不存在");
        }else {
            // 获取到用户id与信息
            Integer id = tabUsers.getId();
            System.out.println("用户id:"+id);
            // 根据id查询用户职位
            List<TabRole> byUid = roleMapper.findByUid(id);
            // 下面循环了一个用户可以有几个职位 用来存储职位的id
            List<Integer> rids = new ArrayList<>();
            // 用来存储用户的职位信息等等
            List<SimpleGrantedAuthority> list = new ArrayList<>();
            for (TabRole tabRole : byUid) {
                // 将登录进去的用户的职位添加到list里访问 /user 可进行查看
                list.add(new SimpleGrantedAuthority("ROLE_"+tabRole.getRcode()));
                // 将当前用户有的职位id存起来用于下方查询
                rids.add(tabRole.getId());
            }
            // 根据当前登录的用户多个职位id来查各个职位对应的菜单
            List<TabMenu> byRoleIds = menuMapper.findByRoleIds(rids);
            for (TabMenu byRoleId : byRoleIds) {
                // 将查到的菜单存到list里
                list.add(new SimpleGrantedAuthority(byRoleId.getMcode()));
            }
            return new User(tabUsers.getUsername(),tabUsers.getPassword(),list);
        }
    }
}

        4. 编写controller层显示用户全部信息 

package com.dys.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.security.Principal;

@RestController
@RequestMapping("user")
public class MyUserController {
    @GetMapping
    public Object getUser(Principal principal){
        return principal;
    }
}

 

        5. 启动类

package com.dys;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.dys.mapper") // 配置mapper位置
public class MySecurityApplication {
    public static void main(String[] args) {
        SpringApplication.run(MySecurityApplication.class);
    }
}

四. 启动 !  ! !

 直接访问user 登录之后即可直接查看到用户的全部信息

访问http://localhost:8080/user会先跳转到 login 登录页面进行登录

 数据库中的账号密码

到此SpringBoot已经学习完毕 

  • 20
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值