编程知识 cdmana.com

SpringSecurity入坑(二)

上一次实现了基于内存验证 缺少了实际的可用性现在修改一下 SpringSecurity的配置来实现基本的数据库验证

pom.xml依赖请参考SpringSecurity入坑(一)的具体依赖这里不做修改

基于数据库做验证,主要的是构建权限验证 废话不多 XX 直接上CODE

User用户表,基于SpringDataJpa构建User用户表

package com.shaojie.authority.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.experimental.Accessors;

import javax.persistence.*;

/**
 * @author ShaoJie
 * @Date 2019年11月25 17:49
 * @Description:
 */
@Data
@Entity
@AllArgsConstructor
@Accessors(chain = true)
@Table(name = "user")
public class User {

    /**
     * 用户的自增 id
     */
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    /**
     * 用户的账号
     */
    @Column(name = "name")
    private String name;

    /**
     * 用户的密码
     */
    @Column(name = "password")
    private String password;

    /**
     * 账号是否启用
     */
    @Column(name = "enable")
    private Boolean enable;

    public User() {

    }

}

Authority权限表 保存用户的权限

package com.shaojie.authority.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.experimental.Accessors;

import javax.persistence.*;

/**
 * @author: ShaoJie
 * @data: 2020年01月06日 20:22
 * @Description: 用户的权限
 */
@Data
@Entity
@AllArgsConstructor
@Accessors(chain = true)
@Table(name = "authority")
public class Authority {

    /**
     * 用户的自增 id
     */
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    /**
     * 用户的账号
     */
    @Column(name = "member_id")
    private Integer memberId;

    /**
     * 用户的权限
     */
    @Column(name = "authority")
    private String authority;

    public Authority() {

    }
}

User数据访问层

package com.shaojie.authority.dao;

import com.shaojie.authority.model.User;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * @author ShaoJie
 * @Date 2019年11月25 18:46
 * @Description:
 */
public interface UserRepository extends JpaRepository<User, Integer> {
    /**
     * 根据用户的账号查询用户
     *
     * @param name 用户的账号
     * @return 用户信息
     */
    User findUserByName(String name);
}

User的业务逻辑层

package com.shaojie.authority.service;

import com.shaojie.authority.model.User;

/**
 * @author ShaoJie
 * @Date 2019年11月25 18:49
 * @Description:
 */
public interface UserService {

    /**
     * 根据用户的账号查询用户
     *
     * @param name 用户的账号
     * @return 用户信息
     */
    User findUserByName(String name);

}

Authority的业务逻辑层

package com.shaojie.authority.dao;

import com.shaojie.authority.model.Authority;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * @author: ShaoJie
 * @data: 2020年01月06日 21:10
 * @Description: 权限 数据访问层
 */
public interface AuthorityRepository extends JpaRepository<Authority, Integer> {
}

Authority的业务逻辑层

package com.shaojie.authority.service;

import com.shaojie.authority.model.Authority;

import java.util.List;

/**
 * @author: ShaoJie
 * @data: 2020年01月06日 21:14
 * @Description: 权限的业务逻辑层
 */
public interface AuthorityService {

    /**
     * 获取用户的权限
     *
     * @param memberId 用户的 id
     * @return 权限的集合
     */
    List<Authority> getUserAuthority(Integer memberId);
}

Authority的业务逻辑 impl

package com.shaojie.authority.service.impl;

import com.shaojie.authority.dao.AuthorityRepository;
import com.shaojie.authority.model.Authority;
import com.shaojie.authority.service.AuthorityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author: ShaoJie
 * @data: 2020年01月06日 21:14
 * @Description: 权限的业务逻辑层
 */
@Service
@Transactional
public class AuthorityServiceImpl implements AuthorityService {

    /**
     * 权限数据访问层
     */
    @Autowired
    private AuthorityRepository authorityRepository;

    /**
     * 获取用户的权限
     *
     * @param memberId 用户的 id
     * @return 权限的集合
     */
    @Override
    public List<Authority> getUserAuthority(Integer memberId) {
        Example<Authority> example = Example.of(new Authority()
                .setMemberId(memberId));
        return authorityRepository.findAll(example);
    }
}

User的业务逻辑 impl

package com.shaojie.authority.security;

import com.shaojie.authority.model.Authority;
import com.shaojie.authority.model.User;
import com.shaojie.authority.service.UserService;
import com.shaojie.authority.service.impl.AuthorityServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.ArrayList;
import java.util.List;

/**
 * @author ShaoJie
 * @Date 2019年11月26 19:48
 * @Description:
 */
@Service
@Transactional
@Slf4j
public class UserDetailsServiceImpl implements UserDetailsService {

    /**
     * 用户 业务逻辑层
     */
    @Autowired
    private UserService userService;

    /**
     * 权限 业务逻辑层
     */
    @Autowired
    private AuthorityServiceImpl authorityService;

    /**
     * 密码加密
     */
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    /**
     * 加载登录 通过用户名查找用户
     *
     * @param userName 登录的用户名称
     * @return 用户信息
     * @throws UsernameNotFoundException 未找到用户登录名称信息
     */
    @Transactional(readOnly = true)
    @Override
    public UserDetails loadUserByUsername(@RequestParam String userName) throws UsernameNotFoundException {
        log.info("{ 当前登录的用户账号:  {} }", userName);
        User user = userService.findUserByName(userName);
        List<GrantedAuthority> authorityList =  new ArrayList<>();
        if (user != null) {
            // 权限集合 当前用户所具有的权限
            authorityList = getUserAuthority(user.getId());
        }
        return new org.springframework.security.core.userdetails.User(user.getName(), bCryptPasswordEncoder.encode(user.getPassword()), authorityList);
    }

    /**
     * 连接数据库 实现 读取权限集合
     *
     * @return 授予的权限
     */
    public List<GrantedAuthority> getUserAuthority(Integer memberId) {
        // 创建权限集合
        List<GrantedAuthority> authorityList = new ArrayList<>();
        // 读取用户的权限集合
        List<Authority> userAuthority = authorityService.getUserAuthority(memberId);
        for (Authority a : userAuthority) {
            GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(a.getAuthority());
            authorityList.add(grantedAuthority);
        }
        return authorityList;
    }

}

这里我直接都写在一起了 ,并没有细划分,其实这个分层不应该是这样,这里只是做基础的展示,所以可能代码上有些糙,有兴趣的自己做调整,下面就是关键的一步了,那就是构建权限验证

构建权限验证

package com.shaojie.authority.security;

import org.springframework.beans.factory.annotation.Autowired;
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.method.configuration.EnableGlobalMethodSecurity;
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;

/**
 * @author ShaoJie
 * @Date 2019/10/25
 */
@Configuration
// 启动 SpringSecurity 的过滤器链
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 密码加密
     *
     * @return
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public UserDetailsServiceImpl userDetailsService() {
        return new UserDetailsServiceImpl();
    }

    /**
     * 用户详细信息 业务逻辑层
     */
    @Autowired
    public UserDetailsServiceImpl userDetailsService;

    /**
     * 授权
     *
     * @param auth
     * @throws Exception
     */
    // 代替配置文件 <security:authentication-manager></security:authentication-manager>
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 基于 数据库验证
        auth.userDetailsService(userDetailsService());
    }

    /**
     * 验证
     *
     * @param http
     * @throws Exception
     */
    // 代替配置文件 <security:http></security:http>
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
                // antMatchers 设置拦截的请求  hasAnyAuthority 对应的权限名称
                // .hasAnyAuthority("PRODUCT_ADD") 用户所具有的权限
                .antMatchers("/product/add").hasAnyAuthority("PRODUCT_ADD")
                .antMatchers("/product/update").hasAnyAuthority("PRODUCT_UPDATE")
                .antMatchers("/product/list").hasAnyAuthority("PRODUCT_LIST")
                .antMatchers("/product/delete").hasAnyAuthority("PRODUCT_DELETE")
                // permitAll 所有的权限都能访问
                .antMatchers("/login").permitAll()
//                .antMatchers("/**")
                // fullyAuthenticated 不允许匿名用户查看
//                .fullyAuthenticated()
                // 设置所有的请求都必须经过验证才能访问
                .anyRequest().authenticated()
                .and()
                // httpbasic 登录
                // .httpBasic();
                // 表单登录
                .formLogin()
                //  登录请求的页面
                .loginPage("/login")
                // 处理登录请求的 地址
                .loginProcessingUrl("/index")
                // 修改 spring 提供的 默认登陆参数
                .usernameParameter("userName")
                .passwordParameter("password")
                .and()
                // 开启记住我功能
                .rememberMe()
                .and()
                // 开启登出
                .logout()
                .and()
                // 禁用跨域的保护
                .csrf().disable();

    }
}

这里需要注意的就是 权限这里 ,现在只 先做到写死权限,系统所具有的哪些权限,这里需要在数据库中配置,后续继续整理,还需要主要的是,需要配置处理登录请求的 地址,基于上一章SpringSecurity入坑(一)页面需要做一下修改:

login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h2>登录页面</h2>
    <form th:action="@{/index}" method="post">
        账号:<input type="text" name="userName" value="1591313226@163.com"><br>
        密码:<input type="password" name="password" value="123456"><br>
        <button type="submit">登录</button>
    </form>
</body>
</html>

需要注意的是,这里的提交的 method 一定要是 post

到这基本的访问数据库,操作权限验证,就到这里,SpringSecurity提供了很多,我们慢慢学习,尽量把这个吸收好。这条路还有很长,需要慢慢的接触,不能太过着急

我也好久没有学习了,很多东西都开始生疏了,共同进步吧,能力有限,能学多少就分享多少,一步一步走,脚踏实体一点,现在生活也过的一般,不舒服,多吃点苦吧,新一年,多加油

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

版权声明
本文为[Shao Jie]所创,转载请带上原文链接,感谢
https://cloud.tencent.com/developer/article/1858545

Scroll to Top