日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

springboot security 权限校验_十二、SpringBoot 优雅的集成Spring Security

發布時間:2025/3/15 javascript 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 springboot security 权限校验_十二、SpringBoot 优雅的集成Spring Security 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

至于什么是Spring security ,主要兩個作用,用戶認證和授權。即我們常說的,用戶只有登錄了才能進行其他操作,沒有登錄的話就重定向到登錄界面。有的用戶有權限執行某一操作,而有的用戶不能執行則是授權。算是一個項目安全框架。和shiro 框架一樣。二者的不同大家可以百度小。Spring security 是Spring家族的一員,所以Springboot算是對Spring security 進行的天然的支持。

之所以這樣說,spring security 被人詬病的配置繁瑣復雜,在springboot中變的簡單起來。如果我們只是demo 效果,可以做到0配置實現。

下面我們就一起來見識一下吧

依賴

我們在pom.xml 文件中引入Spring security 的statter

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency>

測試

我們先來0配置的看看。引入依賴以后,我們創建一個HelloController 內容如下:

@RestController public class HelloController {@RequestMapping("/hello")public String hello(){return "hello world";} }

然后我們啟動項目,按照我們正常的理解,直接訪問

localhost:8080/hello

會返回hello world 。但結果卻是重定向到了/login 。下面的界面是Spring security 自帶的。

其實上面可以看到,Spring security 已經起作用了,沒有登錄不能訪問 /hello 接口。

默認的用戶名為 user;密碼在我們項目啟動時控制臺有打印,每次都會不一樣,隨機生成的。

我們輸入賬號密碼,再試試

可以看到,在登錄之后,我們在請求 /hello 會直接返回hello world , 那是不是只要登錄一次,后面就可以一直訪問呢?當然不是的,登錄成功之后,會將信息保存在session 中,再登錄的時候,就會通過session 校驗,這樣就可以訪問到了,當session過期獲取我們手動清理掉后,就需要重新登錄了。我們來試試。打開控制臺,application 中的cookies 中的jsessionid 清理掉。

我們接著請求試試,可以發現刪除后,就會重新回到登錄界面。

簡單配置用戶和密碼

上面我們使用的默認的用戶名和密碼,但是實際上我們肯定不會這么做的,上面只是說明springboot 完全的集成了Spring security 。下面我們先來簡單的配置用戶名密碼,之所以這樣說,因為我們實際過程中應該還是不會這么用的。之所以要講,讓大家了解的更全面,也為下面鋪墊。

application.properties 中配置

首先我們來簡單的,我們可以直接在application.properties 中配置用戶名和密碼。來代替默認用戶名和密碼的效果。

spring.security.user.name=quellanan spring.security.user.password=123456 spring.security.user.roles=admin

分別是設置用戶名,密碼,角色。我們這里暫時只用了用戶認證,所以角色設不設置無所謂。配置好這些之后我們重啟項目在界面上試試再。

沒有問題,但是沒有什么用,我們實際中是不會這么干的吧。

內存中配置

在內存中配置的話,相對來說要復雜點,我們創建一個config 包,在包下創建SecurityConfig 類繼承 WebSecurityConfigurerAdapter

@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().passwordEncoder(passwordEncoder()) // 指定加密方式.withUser("qaz").password(passwordEncoder().encode("123456")).roles("admin").and().withUser("test").password(passwordEncoder().encode("123456")).roles("USER");}@Beanpublic PasswordEncoder passwordEncoder() {// BCryptPasswordEncoder:Spring Security 提供的加密工具return new BCryptPasswordEncoder();} }

這里我們重寫了configure(AuthenticationManagerBuilder auth) 方法,就是將定義的用戶配置到內存中。這里有一個問題需要說明一下,就是這里配置的話,密碼需要用BCryptPasswordEncoder 加密。如果不加密的話,項目編譯啟動不會報錯,但是登陸的時候就會提示賬號密碼錯誤。還有一個問題就是,如果我們在這配置了,那我們在application.peoperties 中配置的就會失效。

上面說的這兩種方法,其實都是不常用的,我們在實際項目中根本不會在項目中寫死用戶信息的。基本上都是存在數據庫中。所以下面我們就開始講解我們最常用的模式吧。

由于這一類,涉及的較多,就單獨一級標題出來,不放在二級標題里面了。

從數據庫進行用戶認證

既然是用到數據庫,項目中自然要引入數據的配置啦,我這里用的是mysql 和mybatis.這是整個項目成型后的目錄結構,先放出來,大家心里有底,然后一步一步的來。

建庫建表

簡單的三張表,user,roles,roles_user 。

下面是 sql。直接執行就可以

/* Date: 2017-12-26 18:36:12 */CREATE DATABASE `quellanan` DEFAULT CHARACTER SET utf8;USE `quellanan`;SET FOREIGN_KEY_CHECKS=0;-- ---------------------------- -- Table structure for roles -- ---------------------------- DROP TABLE IF EXISTS `roles`; CREATE TABLE `roles` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(32) DEFAULT NULL,PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;-- ---------------------------- -- Records of roles -- ---------------------------- INSERT INTO `roles` VALUES ('1', '超級管理員'); INSERT INTO `roles` VALUES ('2', '普通用戶'); INSERT INTO `roles` VALUES ('3', '測試角色1'); INSERT INTO `roles` VALUES ('4', '測試角色2'); INSERT INTO `roles` VALUES ('5', '測試角色3');-- ---------------------------- -- Table structure for roles_user -- ---------------------------- DROP TABLE IF EXISTS `roles_user`; CREATE TABLE `roles_user` (`id` int(11) NOT NULL AUTO_INCREMENT,`rid` int(11) DEFAULT '2',`uid` int(11) DEFAULT NULL,PRIMARY KEY (`id`),KEY `rid` (`rid`),KEY `roles_user_ibfk_2` (`uid`),CONSTRAINT `roles_user_ibfk_1` FOREIGN KEY (`rid`) REFERENCES `roles` (`id`),CONSTRAINT `roles_user_ibfk_2` FOREIGN KEY (`uid`) REFERENCES `user` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB AUTO_INCREMENT=131 DEFAULT CHARSET=utf8;-- ---------------------------- -- Records of roles_user -- ---------------------------- INSERT INTO `roles_user` VALUES ('1', '1', '1'); INSERT INTO `roles_user` VALUES ('2', '2', '2'); INSERT INTO `roles_user` VALUES ('3', '3', '3'); INSERT INTO `roles_user` VALUES ('4', '1', '4');-- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(64) DEFAULT NULL,`nickname` varchar(64) DEFAULT NULL,`password` varchar(255) DEFAULT NULL,`enabled` tinyint(1) DEFAULT '1',`email` varchar(64) DEFAULT NULL,`userface` varchar(255) DEFAULT NULL,`regTime` datetime DEFAULT NULL,PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8;-- ---------------------------- -- Records of user -- ---------------------------- INSERT INTO `user` VALUES ('1', 'quellanan', '', '$2a$10$Hv0YGLi/siOswCTP236MtOTWbClcM6rN1LCyqwfRmrwCJZqXHsj5a', '1', 'quellanan@qq.com','', '2017-12-08 09:30:22');INSERT INTO `user` VALUES ('2', 'qaz', '', '$2a$10$6H69XLebCrGhHeHzDXEoH.0x8tMFS0XfdDPwI5s.Eu9pbqRpncA.G', '1', 'quellanan@qq.com','', '2017-12-08 09:30:22');INSERT INTO `user` VALUES ('3', 'wsx', '', '$2a$10$6H69XLebCrGhHeHzDXEoH.0x8tMFS0XfdDPwI5s.Eu9pbqRpncA.G', '1', 'quellanan@qq.com','', '2017-12-08 09:30:22');INSERT INTO `user` VALUES ('4', 'test', '', '$2a$10$6H69XLebCrGhHeHzDXEoH.0x8tMFS0XfdDPwI5s.Eu9pbqRpncA.G', '1', 'quellanan@qq.com','', '2017-12-08 09:30:22');SET FOREIGN_KEY_CHECKS=1;

pom.xml 增加依賴

我們首先在原先pom 文件基礎上增加,如下依賴。

<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.0</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>

前面三個是mysql 和mybatis的依賴。lombok 是一個工具類插件。

同時我們需要修改一下pom 文件中的build ,不然我們項目可能會找不到mybatis 的xml文件。

<build><resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource><resource><directory>src/main/resources</directory></resource></resources><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>

配置application.properties

spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://127.0.0.1:3306/quellanan?allowMultiQueries=true&useUnicode=true&characterEncoding=utf8&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=123456 spring.datasource.max-idle=10 spring.datasource.max-wait=10000 spring.datasource.min-idle=5 spring.datasource.initial-size=5

這里如果想要打印mybatis 的sql 日志??梢蕴砑右粋€mybatis-config.xml文件,和application.properties 同目錄

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration><settings><setting name="logImpl" value="STDOUT_LOGGING" /></settings> </configuration>

并在application.properties 中加上

mybatis.config-location=classpath:/mybatis-config.xml

entry

我們在entry 包下創建 RoleEntry。代碼如下:

@Getter @Setter public class RoleEntry {private Long id;private String name; }

我們在創建 UserEntry ,但是UserEntry 比較特殊,因為我們需要使用Spring security 。所以這里,UserEntry 需要實現 UserDetails。代碼如下:

@Setter @Getter public class UserEntry implements UserDetails {private Long id;private String username;private String password;private String nickname;private boolean enabled;private List<RoleEntry> roles;private String email;private String userface;private Timestamp regTime;/*** 獲取角色權限* @return*/@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {List<GrantedAuthority> authorities = new ArrayList<>();for (RoleEntry role : roles) {authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));}return authorities;}/*** 獲取密碼* @return*/@Overridepublic String getPassword() {return password;}/*** 獲取用戶名* @return*/@Overridepublic String getUsername() {return username;}/*** 用戶賬號是否過期*/@Overridepublic boolean isAccountNonExpired() {return true;}/*** 用戶賬號是否被鎖定*/@Overridepublic boolean isAccountNonLocked() {return true;}/*** 用戶密碼是否過期*/@Overridepublic boolean isCredentialsNonExpired() {return true;}/*** 用戶是否可用*/@Overridepublic boolean isEnabled() {return enabled;} }

可以看到,基本上都是重寫的方法。也比較簡單。

mapper

這里我將xml 文件和接口放在一起了,你們也可以在resources 中創建一個mapper,將xml 文件放在哪里。mapper層沒有什么好說的,是mybatis 的一些知識,我們這里講代碼貼出來。

RolesMapper

@Mapper public interface RolesMapper {List<RoleEntry> getRolesByUid(Long uid); }

RolesMapper.xml

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.zlflovemm.security.mapper.RolesMapper"><select id="getRolesByUid" parameterType="long" resultType="com.zlflovemm.security.entry.RoleEntry">SELECT r.* FROM roles r,roles_user ru WHERE r.`id`=ru.`rid` AND ru.`uid`=#{uid}</select> </mapper>

UserMapper

@Mapper public interface UserMapper {UserEntry loadUserByUsername(@Param("username") String username); }

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.zlflovemm.security.mapper.UserMapper"><select id="loadUserByUsername" resultType="com.zlflovemm.security.entry.UserEntry">SELECT * FROM user WHERE username=#{username}</select> </mapper>

service

在service 層我們要注意一點,我們需要實現 UserDetailsService 接口。我們先創建一個UserService 繼承 UserDetailsService。然后創建一個UserServiceImpl 來時實現UserService 從而達到實現UserDetailsService的目的。這樣做是為了保證項目結構的統一層次。

UserService

public interface UserService extends UserDetailsService { }

UserServiceImpl

@Service @Slf4j @Transactional public class UserServiceImpl implements UserService {@AutowiredUserMapper userMapper;@AutowiredRolesMapper rolesMapper;@Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {UserEntry user = userMapper.loadUserByUsername(s);if (user == null) {//避免返回null,這里返回一個不含有任何值的User對象,在后期的密碼比對過程中一樣會驗證失敗return new UserEntry();}//查詢用戶的角色信息,并返回存入user中List<RoleEntry> roles = rolesMapper.getRolesByUid(user.getId());user.setRoles(roles);return user;} }

可以看到,主要是為了實現 loadUserByUsername的方法。在這個方法中我們 loadUserByUsername和getRolesByUid 就是我們在mapper 定義的查詢數據庫數據的方法。

SecurityConfig

前面做了這么多,其實都是準備工作,主要的目的就是提供一個Bean 。做完上面這些,我們再回到 SecurityConfig 中,其實我們現在需要修改的很少了。我們將用戶寫在內存的方法注釋掉。通過數據庫查詢。

@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter {@AutowiredUserService userService;@Beanpublic PasswordEncoder passwordEncoder() {// BCryptPasswordEncoder:Spring Security 提供的加密工具return new BCryptPasswordEncoder();}@Overridepublic void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userService).passwordEncoder(passwordEncoder());//passwoldEncoder是對密碼的加密處理,如果user中密碼沒有加密,則可以不加此方法。注意加密請使用security自帶的加密方式。}}

可以和開始的 SecurityConfig 文件對比下,其實你就是多了一個userService,然后configure(AuthenticationManagerBuilder auth)中是通過userService 進行校驗的。

測試

好了,其實到這里,我們就已經完成了,我們啟動項目,就可以看到和之前寫在內存中達到一樣的效果。

過濾

以為到這就完了,其實還有一點哈哈。我們現在是所有的接口都需要先登錄才能訪問,沒有登錄的話就跳轉到login界面。實際上我們肯定有些是不需要認證也可以訪問的,比如以下靜態文件或者注冊的請求。所以我們還是要配置一下過濾。

其實也很簡單,一樣的在 SecurityConfig 文件中 重寫 configure(HttpSecurity http) 方法。這里我直接參考官網上的。https://spring.io/guides/gs/securing-web/

該configure(HttpSecurity)方法定義應保護哪些URL路徑,不應該保護哪些URL路徑。具體而言,“ /”和“ / home”路徑配置為不需要任何身份驗證。所有其他路徑必須經過驗證。用戶成功登錄后,他們將被重定向到之前要求身份驗證的頁面。有一個由指定的自定義“ /登錄”頁面loginPage(),每個人都可以查看它。

我們代碼中 把 loginPage("/login") 注釋掉就好了,如果不注釋的話,就需要我們自己寫login 界面和請求。我們這里就用框架自帶的。

@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/", "/hello").permitAll().anyRequest().authenticated().and().formLogin()//.loginPage("/login").permitAll().and().logout().permitAll();}

這樣配置就說明 /hell 和 / 請求不會攔截,其他的請求,需要先登錄才能訪問。為了更方便的看到效果,我們在HelloController 中再加兩個方法

@RequestMapping("/hello2")public String hello2(){return "hello adada";}@RequestMapping("/")public String hello3(){return " qazqeee";} }

現在我們啟動來看下效果。

證明我們配置的過濾是有效果的。

番外

到此算是差不多結束了,其實還有很多知識點,不是一篇文章能講完的,這里算是拋轉引玉,希望對大家有幫助。后面我也會持續更新

好了,源碼我上傳到github 上啦https://github.com/QuellanAn/security

后續加油?

歡迎大家關注個人公眾號 "程序員愛酸奶"

分享各種學習資料,包含java,linux,大數據等。資料包含視頻文檔以及源碼,同時分享本人及投遞的優質技術博文。

如果大家喜歡記得關注和分享喲?

http://weixin.qq.com/r/lSpcRJ-EBsJ5rdsn93_H (二維碼自動識別)

總結

以上是生活随笔為你收集整理的springboot security 权限校验_十二、SpringBoot 优雅的集成Spring Security的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。