天天看點

一、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入門

繼續閱讀