javascript
【Spring框架家族】Spring--Security权限控制密码加密
Spring Security簡介
Spring Security是 Spring提供的安全認證服務的框架。 使用Spring Security可以幫助我們來簡化認證
和授權的過程。官網:https://spring.io/projects/spring-security
屬于Spring家族一員,使用這個框架必須基于Spring
對應的maven坐標:
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>5.0.5.RELEASE</version> </dependency>常用的權限框架除了Spring Security,還有Apache的shiro框架。
Spring Security基本入門
配置web.xml:在web.xml中主要配置SpringMVC的DispatcherServlet和用于整合第三方框架的
DelegatingFilterProxy,用于整合Spring Security。
<filter> <!--DelegatingFilterProxy用于整合第三方框架 整合Spring Security時過濾器的名稱必須為springSecurityFilterChain, 否則會拋出NoSuchBeanDefinitionException異常因為框架底層會根據這個過濾器名稱獲取一個Bean對象(Security的過濾器),它會加載很多的BeanSpring會根據傳入的值,確定加載的對象,這個值是Spring容器中定義好的名稱--> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 指定加載的配置文件 ,通過參數contextConfigLocation加載 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-security.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>配置spring-security.xml:主要配置Spring Security的攔截規則和認證管理器
<!-- http:用于定義相關權限控制,指定哪些資源不需要進行權限校驗,可以使用通配符--><!-- 配置那些資源匿名可以訪問(不需要登錄)--><security:http security="none" pattern="/pages/a.html"/><!-- pages包下所有資源都可以訪問--><security:http security="none" pattern="/pages/**"/><!--http:用于定義相關權限控制auto-config:是否自動配置設置為true時框架會提供默認的一些配置,例如提供默認的登錄頁面、登出 處理等設置為false時需要顯示提供登錄表單配置,否則會報錯use-expressions:用于指定intercept-url中的access屬性是否使用表達式來描述權限表達式:hasRole('ROLE_ADMIN')ROLE_ADMIN:普通字符串,建議與數據庫角色或者權限關鍵字保持一致--><security:http auto-config="true" use-expressions="true"><security:headers><!--設置在頁面可以通過iframe訪問受保護的頁面,默認為不允許訪問--><security:frame-options policy="SAMEORIGIN"></security:frame-options></security:headers><!--intercept-url:定義一個攔截規則pattern:對哪些url進行權限控制,/** 表示攔截所有請求access:在請求對應的URL時需要什么權限,默認配置時它應該是一個以逗號分隔的角色列表,請求的用戶只需擁有其中的一個角色就能成功訪問對應的URL默認三種取值:IS_AUTHENTICATED_ANONYMOUSLY :不用登錄可以訪問資源IS_AUTHENTICATED_REMEMBERED: 只有自動登錄才可以訪問資源IS_AUTHENTICATED_FULLY: 只有登錄成功才可以訪問資源--><security:intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')" /><!--只要認證通過就可以訪問--> <security:intercept-url pattern="/index.jsp" access="isAuthenticated()" /> <security:intercept-url pattern="/a.html" access="isAuthenticated()" /> <!--擁有add權限就可以訪問b.html頁面--> <security:intercept-url pattern="/b.html" access="hasAuthority('add')" /><!--擁有ROLE_ADMIN角色就可以訪問c.html頁面--> <security:intercept-url pattern="/c.html" access="hasRole('ROLE_ADMIN')" /> <security:intercept-url pattern="/**" access="hasRole('角色1' or '角色2')" /><security:intercept-url pattern="/**" access="hasAnyRole('角色1','角色2')" /><!--method="POST":必須POST請求requires-channel="https":必須是https協議--> <security:intercept-url pattern="/**" method="POST" requires-channel="https"/><!--指定端口號--> <security:port-mappings><security:port-mapping http="666" https="888"/></security:port-mappings><!--擁有ROLE_ADMIN角色就可以訪問d.html頁面, 注意:此處雖然寫的是ADMIN角色,框架會自動加上前綴ROLE_--> <security:intercept-url pattern="/d.html" access="hasRole('ADMIN')" /><!-- 如果要使用自己頁面作為登錄頁面,必須配置登錄表單,頁面提交的登錄表單請求由框架負責處理--><!--login-page:指定登錄頁面訪問URLusername-parameter:指定用戶名輸入框,參數與表單保持一致,不寫,表單name必須是usernamepassword-parameter:指定密碼輸入框,參數與表單保持一致,不寫,表單name必須是passwordlogin-processing-url:指定表單的提交地址,請求default-target-url:登錄成功,默認跳轉頁面authentication-failure-url:登錄失敗,默認跳轉頁面authentication-success-forward-url:登錄成功,轉發到這個頁面如果兩個登錄成功跳轉頁面屬性不寫,那么登陸成功之后會跳轉到本來請求的頁面--><security:form-loginlogin-page="/login.html"username-parameter="username"password-parameter="password"login-processing-url="/login.do"default-target-url="/index.html"authentication-failure-url="/login.html"authentication-success-forward-url="/pages/a.html" /><!--csrf:對應CsrfFilter過濾器,disabled:是否啟用CsrfFilter過濾器,框架默認提交csrf一串字符串,驗證是否為框架自帶的,如果使用自定義登錄頁面需要關閉此項,框架驗證不通過,認為不是合法請求,登錄操作會被禁用(403)--> <security:csrf disabled="true"/></security:http><!--authentication-manager:認證管理器,用于處理認證操作--><security:authentication-manager><!--authentication-provider:認證提供者,執行具體的認證邏輯配置認證的用戶和密碼,完成認證,必須告訴框架正確的用戶名和密碼是什么,對應的權限有哪些框架才可以拿著用戶輸入的用戶名密碼和配置的用戶名密碼比較可以直接寫死用戶名密碼和權限,也可以配置Bean對象,從數據庫獲取但是Bean對象必須實現UserDetailsService接口--><security:authentication-provider user-service-ref="userService"><!--user-service:用于獲取用戶信息,提供給authentication-provider進行認證--><security:user-service><!--user:定義用戶信息,可以指定用戶名、密碼、角色,后期可以改為從數據庫查詢 用戶信息{noop}:表示當前使用的密碼為明文authorities:權限--><security:user name="admin"password="{noop}admin"authorities="ROLE_ADMIN"/></security:user-service></security:authentication-provider></security:authentication-manager><bean id="userService" class="com.lx.service.SpringSecurityUserService"/></beans>要從數據庫動態查詢用戶信息,就必須按照spring security框架的要求提供一個實現
UserDetailsService接口的實現類,并按照框架的要求進行配置即可。框架會自動調用實現類中的方法
并自動進行密碼校驗。
public class SpringSecurityUserService implements UserDetailsService {// 根據用戶名查詢用戶信息@Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {System.out.println("用戶輸入的用戶名:" + s);return null;}}實現流程
-
瀏覽器指定發送請求login.do,配置<security:form-login login-processing-url="/login.do"/>,一旦發送請求,框架自動攔截,接收用戶名和密碼
-
框架定義好了接口UserDetailsService,指定方法loadUserByUsername,只需要實現此接口,框架會自己去調用方法,
-
返回用戶對象org.springframework.security.core.userdetails.User,框架定義好的user,框架自己判斷用戶名密碼是否正確
-
查詢Dao,根據用戶名查詢,沒有密碼,密碼框架拿著,也就是要求用戶表,用戶名必須唯一
Spring Security對密碼進行加密
bcrypt:將salt隨機并混入最終加密后的密碼,驗證時也無需單獨提供之前的salt,從而無需單獨處理
salt問題
加密后的格式一般為:
$2a$10$/bTVvqqlH9UiE0ZJZ7N2Me3RIgUCdgMheyTgV0B4cMCSokPa.6oCa加密后字符串的長度為固定的60位。其中:$是分割符,無意義;2a是bcrypt加密版本號;10是cost的
值;而后的前22位是salt值;再然后的字符串就是密碼的密文了。
每次生成的密文不一樣
實現步驟:
在spring-security.xml文件中指定密碼加密對象
<!--認證管理器,用于處理認證操作--><security:authentication-manager><!--認證提供者,執行具體的認證邏輯--><security:authentication-provider user-service-ref="userService"><!--指定密碼加密策略--><security:password-encoder ref="passwordEncoder" /></security:authentication-provider></security:authentication-manager><!--配置密碼加密對象--><bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />@Autowiredprivate BCryptPasswordEncoder passwordEncoder;// 使用bcrypt提供的方法對密碼進行加密user.setPassword(passwordEncoder.encode("admin"));注解方式權限控制
spring-security.xml文件中配置
<!--開啟spring注解使用--><context:annotation-config/><!--開啟springMVC注解使用--><mvc:annotation-driven/><!--配置組件掃描,用于掃描Controller--><context:component-scan base-package="com.itheima.controller"/><!--開啟注解方式權限控制--> <security:global-method-security pre-post-annotations="enabled" />創建Controller類并在Controller的方法上加入注解進行權限控制
@RestController@RequestMapping("/hello")public class HelloController {@RequestMapping("/add")// 表示用戶必須擁有add權限才能調用當前方法@PreAuthorize("hasAuthority('add')")// 先執行方法,在進行權限校驗@PostAuthorize("hasAuthority('CHECKITEM_DELETE')")public String add(){System.out.println("add.......");return "success";}@RequestMapping("/delete")//表示用戶必須擁有ROLE_ADMIN角色才能調用當前方法@PreAuthorize("hasRole('ROLE_ADMIN')")public String delete(){System.out.println("delete.......");return "success";}}獲取用戶登錄的用戶名
// 獲取當前登錄用戶的用戶名@RequestMapping("/getUsername")public Result getUsername(){// Spring security完成認證后,會將當前用戶信息保存到框架提供的上下文對象,存入session中User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();System.out.println("user = " + user);if (user != null){String username = user.getUsername();return new Result(true, MessageConstant.GET_USERNAME_SUCCESS,username);}return new Result(false, MessageConstant.GET_USERNAME_SUCCESS);}退出登錄
<!--logout:退出登錄logout-url:退出登錄操作對應的請求路徑logout-success-url:退出登錄后的跳轉頁面invalidate-session:銷毀session--> <security:logout logout-url="/logout.do"logout-success-url="/login.html"invalidate-session="true"/>錯誤信息返回
security:access-denied-handler ref='bean對象'// 錯誤信息類必須實現AccessDeniedHandler接口// 重寫handle方法異步請求,響應回去數據都是異步請求回調函數中轉換Json處理中文亂碼httpServletResponse.setContentType("application/json;charset=utf-8")總結
以上是生活随笔為你收集整理的【Spring框架家族】Spring--Security权限控制密码加密的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【十大经典排序算法】java实现--选择
- 下一篇: 【SSM框架系列】SpringMVC的文