SpringBoot2 - SpringSecurity

簡(jiǎn)介

SpringSecurity是專門針對(duì)基于Spring項(xiàng)目的安全框架贪婉,充分利用了依賴注入和AOP來(lái)實(shí)現(xiàn)安全管控洪橘。

SpringSecurity框架有兩個(gè)概念認(rèn)證和授權(quán)凫乖,認(rèn)證可以訪問(wèn)系統(tǒng)的用戶鹿鳖,而授權(quán)則是用戶可以訪問(wèn)的資源粱锐。

構(gòu)建項(xiàng)目

  1. 訪問(wèn)地址:http://start.spring.io
  2. 添加Web樱蛤、MySQL钮呀、JPA、Druid刹悴、Security行楞、JSP依賴

pom.xml

<?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.gala</groupId>
    <artifactId>security</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>security</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.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>
        <!--Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--SpringSecurity -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
        </dependency>
        <!--SpringDataJPA -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!--MySQL -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.9</version>
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>

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

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

新增配置文件application.yml

spring:
 datasource:
  type: com.alibaba.druid.pool.DruidDataSource
  driver-class-name: com.mysql.jdbc.Driver
  url: jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8
  username: root
  password: 123456
  #配置監(jiān)控統(tǒng)計(jì)攔截的filters
  filters: stat,wall,log4j
  #最大活躍數(shù)
  maxActive: 20
  #初始化數(shù)量
  initialSize: 1
  #最大連接等待超時(shí)時(shí)間
  maxWait: 60000
  #打開PSCache,并指定每個(gè)連接PSCache的大小
  poolPreparedStatements: true
  maxPoolPreparedStatementPerConnectionSize: 20
  #通過(guò)connectionProperties屬性打開mergeSql功能
  connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
  minldle: 1
  timeBetweenEvictionRunsMillis: 60000
  minEvictableldleTimeMillis: 300000
  validationQuery: select 1 from dual
  testWhiledle: true
  testOnBorrow: false
  testOnReturn: false
 jpa:
  properties:
   hibernate:
    show_sql: true
    format_sql: true
 mvc:
  view:
   prefix: /WEB-INF/views/
   suffix: .jsp

建表及初始化數(shù)據(jù)

-- ----------------------------
-- Table structure for ss_user 用戶
-- ----------------------------
DROP TABLE IF EXISTS `ss_user`;
 
CREATE TABLE `ss_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `username` varchar(10) DEFAULT NULL COMMENT '用戶名稱',
  `password` varchar(10) DEFAULT NULL COMMENT '用戶密碼',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

insert  into `ss_user`(`id`,`username`,`password`) values (1,'admin','123456'),(2,'user','123456');

-- ----------------------------
-- Table structure for ss_user 角色
-- ----------------------------
 
DROP TABLE IF EXISTS `ss_role`;
 
CREATE TABLE `ss_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `role_name` varchar(10) DEFAULT NULL COMMENT '角色名稱',
  `role_description` varchar(20) DEFAULT NULL COMMENT '角色描述',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
 
insert  into `ss_role`(`id`,`role_name`,`role_description`) values (1,'ROLE_USER','普通用戶'),(2,'ROLE_ADMIN','管理員');
 
-- ----------------------------
-- Table structure for ss_user_role 用戶角色關(guān)系
-- ----------------------------
DROP TABLE IF EXISTS `ss_user_role`;
 
CREATE TABLE `ss_user_role` (
  `user_id` int(11) DEFAULT NULL COMMENT '用戶ID',
  `role_id` int(11) DEFAULT NULL COMMENT '角色I(xiàn)D'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
insert  into `ss_user_role`(`user_id`,`role_id`) values (1,1),(1,2),(2,1);

創(chuàng)建實(shí)體類

  1. User.java
package com.gala.security.entity;

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

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

/**
 * UserDetails是SpringSecurity驗(yàn)證框架內(nèi)部提供的用戶驗(yàn)證接口
 */
@Entity
@Table(name = "ss_user")
public class User implements Serializable, UserDetails {

    private static final long serialVersionUID = -5445460877560833224L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String username;

    private String password;

    @Transient
    Collection<GrantedAuthority> authorities;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "ss_user_role", joinColumns = { @JoinColumn(name = "user_id") }, inverseJoinColumns = { @JoinColumn(name = "role_id") })
    private List<Role> roles;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setAuthorities(Collection<GrantedAuthority> authorities) {
        this.authorities = authorities;
    }

    public List<Role> getRoles() {
        return roles;
    }

    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }

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

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

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

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

    /**
     * 將我們定義的角色列表添加到授權(quán)的列表內(nèi)
     */
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
        List<Role> roles = getRoles();
        for (Role role : roles) {
            System.out.println("獲取用戶角色-->" + role.getRoleName());
            auths.add(new SimpleGrantedAuthority(role.getRoleName()));
        }
        return auths;
    }

}
  1. Role.java
package com.gala.security.entity;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "ss_role")
public class Role implements Serializable {

    private static final long serialVersionUID = -2550502360099906919L;

    private Long id;

    private String roleName;

    private String roleDescription;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public String getRoleDescription() {
        return roleDescription;
    }

    public void setRoleDescription(String roleDescription) {
        this.roleDescription = roleDescription;
    }

}

創(chuàng)建接口

package com.gala.security.jpa;

import org.springframework.data.jpa.repository.JpaRepository;

import com.gala.security.entity.User;

public interface UserDao extends JpaRepository<User, Long> {

    public User findByUsername(String username);

}

SpringSecurity用戶認(rèn)證

密碼加密

package com.gala.security;

import org.springframework.security.crypto.password.PasswordEncoder;

public class MyPasswordEncoder implements PasswordEncoder {

    @Override
    public String encode(CharSequence rawPassword) {
        return rawPassword.toString();
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        return encodedPassword.equals(rawPassword.toString());
    }
}

認(rèn)證配置

package com.gala.security.service;

import java.util.Collection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
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 com.gala.security.entity.User;
import com.gala.security.jpa.UserDao;

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private UserDao userDao;

    /**
     * 自定義用戶登錄
     */
    @SuppressWarnings("unchecked")
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userDao.findByUsername(username);
        if (user == null) {
            System.out.println("獲取用戶信息" + username + "失敗");
            throw new UsernameNotFoundException("用戶名:" + username + "不存在");
        }

        Collection<GrantedAuthority> authorities = (Collection<GrantedAuthority>) user.getAuthorities();

        user.setAuthorities(authorities);
        System.out.println("獲取用戶" + username + "信息成功土匀!");
        return user;
    }
}

配置SpringBoot內(nèi)的MVC控制器跳轉(zhuǎn)

package com.gala.security.conf;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 配置SpringBoot內(nèi)的MVC控制器跳轉(zhuǎn)
 */
@Configuration
public class MVCConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/login").setViewName("login");
    }

}

新增控制器

package com.gala.security.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class LoginController {

    @RequestMapping("/index")
    public String index() {
        return "index";
    }

}

新增JSP

  1. 登錄頁(yè)面
<%@ page contentType="text/html;charset=UTF-8" language="java"%>
<html>
<head>
<title>登錄界面</title>
</head>
<body>
    <form action="/login" method="post">
        用戶名:<input type="text" name="username" /><br />
        密碼:<input type="text" name="password" /><br />
        <input type="submit" value="登錄" />
    </form>
</body>
</html>

2.登錄成功頁(yè)面

<%@ page contentType="text/html;charset=UTF-8" language="java"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<html>
<head>
<title>首頁(yè)</title>
</head>
<body>
    登錄成功!
    <sec:authorize access="hasRole('ROLE_ADMIN')">
        您擁有管理員權(quán)限子房。
    </sec:authorize>
    <br />
    <sec:authorize access="hasRole('ROLE_USER')">
        您擁有用戶權(quán)限。
    </sec:authorize>
</body>
</html>

測(cè)試

啟動(dòng)項(xiàng)目就轧,訪問(wèn):http://127.0.0.1:8080/index


輸入用戶名密碼admin/123456

項(xiàng)目結(jié)構(gòu)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末证杭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子妒御,更是在濱河造成了極大的恐慌解愤,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乎莉,死亡現(xiàn)場(chǎng)離奇詭異送讲,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)惋啃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門哼鬓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人边灭,你說(shuō)我怎么就攤上這事异希。” “怎么了绒瘦?”我有些...
    開封第一講書人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵称簿,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我惰帽,道長(zhǎng)憨降,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任善茎,我火速辦了婚禮券册,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己烁焙,他們只是感情好航邢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著骄蝇,像睡著了一般膳殷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上九火,一...
    開封第一講書人閱讀 51,488評(píng)論 1 302
  • 那天赚窃,我揣著相機(jī)與錄音,去河邊找鬼岔激。 笑死勒极,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的虑鼎。 我是一名探鬼主播辱匿,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼炫彩!你這毒婦竟也來(lái)了匾七?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤江兢,失蹤者是張志新(化名)和其女友劉穎昨忆,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體杉允,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡邑贴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了叔磷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片痢缎。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖世澜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情署穗,我是刑警寧澤寥裂,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站案疲,受9級(jí)特大地震影響封恰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜褐啡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一诺舔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦低飒、人聲如沸许昨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)糕档。三九已至,卻和暖如春拌喉,著一層夾襖步出監(jiān)牢的瞬間速那,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工尿背, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留端仰,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓田藐,卻偏偏與公主長(zhǎng)得像荔烧,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子坞淮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理茴晋,服務(wù)發(fā)現(xiàn),斷路器回窘,智...
    卡卡羅2017閱讀 134,656評(píng)論 18 139
  • 在開發(fā)React Native的App的時(shí)候诺擅,你會(huì)遇到很多情況是原生的視圖組件已經(jīng)開發(fā)好了的。有的是系統(tǒng)的SDK提...
    董董董董董董董董董大笨蛋閱讀 1,104評(píng)論 2 1
  • 讀大學(xué)的時(shí)候,認(rèn)識(shí)一個(gè)挺博學(xué)的哥們酒觅,姑且稱之為朋友A吧撮执。 朋友A性別男,愛好書和酒舷丹。此人無(wú)書不讀抒钱,對(duì)于酒,更是開心...
    司馬逍遙閱讀 232評(píng)論 0 1
  • 《戰(zhàn)狼3》已開始籌備颜凯。劇情介紹: 冷鋒從非洲回到國(guó)內(nèi)被戰(zhàn)狼召回谋币!得知龍小云被反政府雇傭軍抓獲后并沒(méi)有死去,而是被坦...
    ailimg閱讀 320評(píng)論 0 0