天天看点

一、Spring Security入门

pom

<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.liaoxiang</groupId>
    <artifactId>spring-security</artifactId>
    <version>1.0.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

    </dependencies>

</project>
           

其他需要用到的后面再添加

权限控制涉及到主要数据库表结构:

一、Spring Security入门

menu表为资源表,即用户能访问的资源,url为后台接口的url pattern,将来用于和具体的请求进行对比,path为前端页面路由路径,component为具体组件,登陆成功之后,根据该用户的角色信息,获取可以访问的资源菜单,渲染到页面

一、Spring Security入门

其他的表数据为测试数据,不再叙述

在注释掉springsecurity依赖的情况下,能够通过接口正常获取数据

一、Spring Security入门

在取消注释之后,再次访问,跳转到了一个登陆页面

一、Spring Security入门

用户名为:user ,密码:日志中输出的密码

一、Spring Security入门

成功获取数据

一、Spring Security入门

这里使用的是Spring Security为我们生成的用户名和密码,下面我们使用自己数据中的用户来登陆

新建一个service类

UserLoginService

,这个类要实现一个接口

UserDetailsService

,这是Spring Security处理用户登陆的一个接口,实现接口里的方法:

UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
           

这个方法接收一个用户名,然后返回一个实现了

UserDetails

接口的对象,下面看一下这个接口里定义的内容:

public interface UserDetails extends Serializable {
	//用户权限(角色)的集合
	Collection<? extends GrantedAuthority> getAuthorities();
	//密码
	String getPassword();
	//用户名
	String getUsername();
	//账户是否未过期
	boolean isAccountNonExpired();
	//账户是否未锁定
	boolean isAccountNonLocked();
	//密码是否为过期
	boolean isCredentialsNonExpired();
	//账户是否激活
	boolean isEnabled();
}
           

UserLoginService :

package com.liaoxiang.service;

import com.liaoxiang.mapper.UserMapper;
import com.liaoxiang.model.User;
import org.springframework.beans.factory.annotation.Autowired;
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;

/**
 * @auther Mr.Liao
 * @date 2019/8/19 14:57
 */
@Service
public class UserLoginService implements UserDetailsService {
    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //如果User为null,就会抛出异常信息:UsernameNotFoundException
        User user = userMapper.findUserByUserName(username);
        return user;
    }
}

           

当执行

loadUserByUsername()

后,返回一个

UserDetails

的实现类对象,Spring Security就会拿着上面这些信息去判断,密码是否正确,几个boolean返回值的方法是否为true,从而来确定是否让用户登陆,而这些用户的信息应该都是我们数据库中用户的信息,因此我们可以让自己的用户实体类来实现

UserDetails

接口:

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import lombok.ToString;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @auther Mr.Liao
 * @date 2019/8/18 17:18
 */
@Data
@ToString
public class User implements UserDetails {
    private Integer userId;
    private String userName;
    private String password;
    private String name;
    private List<Role> roles;
    private boolean enabled;

    /**
     * 账户的权限信息
     * @return
     */
    @JsonIgnore
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        ArrayList<GrantedAuthority> authorities = new ArrayList<>();
        for (Role role : roles) {
            authorities.add(new SimpleGrantedAuthority(role.getRoleAuthority()));
        }
        return authorities;
    }

    @Override
    public String getUsername() {
        return userName;
    }

    @JsonIgnore
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @JsonIgnore
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @JsonIgnore
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return enabled;
    }
}
           

在处理用户的权限信息时,需要一个实现了

GrantedAuthority

接口的实现类对象,我们使用

SimpleGrantedAuthority

,它实现了

GrantedAuthority

,需要注意的是,在Spring Security中角色信息以

ROLE_

开头,因此在角色表中要使用注意角色的权限名称:

一、Spring Security入门
public final class SimpleGrantedAuthority implements GrantedAuthority {

	private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

	private final String role;

	public SimpleGrantedAuthority(String role) {
		Assert.hasText(role, "A granted authority textual representation is required");
		this.role = role;
	}

	@Override
	public String getAuthority() {
		return role;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}

		if (obj instanceof SimpleGrantedAuthority) {
			return role.equals(((SimpleGrantedAuthority) obj).role);
		}

		return false;
	}

	@Override
	public int hashCode() {
		return this.role.hashCode();
	}

	@Override
	public String toString() {
		return this.role;
	}
}
           

添加配置信息:

userDetailsService

的实现类,和密码加密解密工具类

BCryptPasswordEncoder

这个我们在启动类中new了一个添加到IOC容器,在添加用户时,加密了密码,登陆时需要用来解密数据库密码和登陆时输入的密码进行比较

package com.liaoxiang.config;

import com.liaoxiang.service.UserLoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * @auther Mr.Liao
 * @date 2019/8/18 22:34
 */
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserLoginService userLoginService;
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userLoginService)
                .passwordEncoder(bCryptPasswordEncoder);
    }
}
           

再次通过浏览器访问获取数据,跳转到登陆页,此时输入用户名和密码就是添加用户时的用户名和密码

一、Spring Security入门
一、Spring Security入门

继续阅读