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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > javascript >内容正文

javascript

Spring Security使用

發(fā)布時(shí)間:2023/12/13 javascript 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring Security使用 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Spring Security

在web應(yīng)用開發(fā)中,安全無疑是十分重要的,選擇Spring Security來保護(hù)web應(yīng)用是一個(gè)非常好的選擇。

Spring Security 是spring項(xiàng)目之中的一個(gè)安全模塊,可以非常方便與spring項(xiàng)目無縫集成。特別是在spring boot項(xiàng)目中加入spring security更是十分簡(jiǎn)單。本篇我們介紹spring security,以及spring security在web應(yīng)用中的使用。

一個(gè)例子入門

假設(shè)我們現(xiàn)在創(chuàng)建好了一個(gè)springboot的web應(yīng)用,有一個(gè)控制器如下:

@Controller public class AppController {@RequestMapping("/hello")@ResponseBodyString home() {return "Hello ,spring security!";} }

我們啟動(dòng)應(yīng)用,假設(shè)端口是8080,那么當(dāng)我們?cè)跒g覽器訪問http://localhost:8080/hello的時(shí)候可以在瀏覽器看到Hello ,spring security!。

加入spring security 保護(hù)應(yīng)用

此時(shí),/hello是可以自由訪問。假設(shè),我們需要具有某個(gè)角色的用戶才能訪問的時(shí)候,我們可以引入spring security來進(jìn)行保護(hù)。加入如下maven依賴,并重啟應(yīng)用:

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

再次訪問/hello,我們可以得到一個(gè)http-basic的認(rèn)證彈窗,如下:

?

代碼如下:

<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'> <h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'> <table><tr><td>User:</td><td><input type='text' name='username' value=''></td></tr><tr><td>Password:</td><td><input type='password' name='password'/></td></tr><tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr><input name="_csrf" type="hidden" value="635780a5-6853-4fcd-ba14-77db85dbd8bd" /> </table> </form></body></html>

我們可以發(fā)現(xiàn),這里有個(gè)form 。action=”/login”,這個(gè)/login是spring security提供的。form表單提交了三個(gè)數(shù)據(jù):

username 用戶名? ?password 密碼? ?_csrf CSRF保護(hù)方面的內(nèi)容

說明spring security 已經(jīng)起作用了。這時(shí),它為你生成了賬號(hào)和密碼,在內(nèi)存中。

但是,我們不可能只是這么使用它,我們?nèi)绾瓮ㄟ^訪問數(shù)據(jù)庫(kù)來登錄,驗(yàn)證權(quán)限呢?

接下來通過一個(gè)實(shí)例繼續(xù)深入。

demo項(xiàng)目權(quán)限介紹

我們通過一個(gè)很簡(jiǎn)單的項(xiàng)目來認(rèn)識(shí)一下Spring Security。

index.html:社區(qū)首頁(yè)(只有四個(gè)鏈接)----------任何人都可以訪問

discuss.html:帖子詳情頁(yè)面(只有一句話)------任何人都可以訪問

letter.html:私信列表(只有一句話)-------只有登陸后的用戶才能訪問

admin.html:管理員頁(yè)面(只有一句話)----只有管理員才能訪問

login.html:登陸頁(yè)面(有表單)----------------不符合要求時(shí),可以登錄

我們的目的,就是把這些權(quán)限管理起來。

?

靜態(tài)頁(yè)面代碼展示

?

下面展示一下這些頁(yè)面的代碼:

index.html:社區(qū)首頁(yè)(只有四個(gè)鏈接)

<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head><meta charset="UTF-8"><title>首頁(yè)</title> </head> <body><h1>社區(qū)首頁(yè)</h1><ul><li><a th:href="@{/discuss}">帖子詳情</a></li><li><a th:href="@{/letter}">私信列表</a></li><li><a th:href="@{/loginpage}">登錄</a></li><li><a th:href="@{/loginpage}">退出</a></li></ul> </body> </html>

discuss.html:帖子詳情頁(yè)面(只有一句話)

<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head><meta charset="UTF-8"><title>帖子</title> </head> <body><h1>帖子詳情頁(yè)面</h1> </body> </html>

letter.html:私信列表(只有一句話)

<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head><meta charset="UTF-8"><title>私信</title> </head> <body><h1>私信列表頁(yè)面</h1> </body> </html>

admin.html:管理員頁(yè)面(只有一句話)

<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head><meta charset="UTF-8"><title>管理員</title> </head> <body><h1>管理員專屬頁(yè)面</h1> </body> </html>

login.html:登陸頁(yè)面(有表單)

<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head><meta charset="UTF-8"><title>登錄</title> </head> <body><h1>登錄社區(qū)</h1><form method="post" action="#"><p style="color:red;"><!--提示信息--></p><p>賬號(hào):<input type="text" ></p><p>密碼:<input type="password" ></p><p>驗(yàn)證碼:<input type="text" ></p><p><input type="submit" value="登錄"></p></form></body> </html>

service層和user的操作

首先要處理我們的用戶user表,寫出獲取權(quán)限的方法。

實(shí)現(xiàn)UserDetails?接口,和接口定義的方法。

方法的作用我都已經(jīng)標(biāo)注在代碼里。

import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails;import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List;public class User implements UserDetails {private int id;private String username;private String password;private String salt;private String email;private int type;private int status;private String activationCode;private String headerUrl;private Date createTime; /* get/set方法 toSring方法 */// true: 賬號(hào)未過期.@Overridepublic boolean isAccountNonExpired() {return true;}// true: 賬號(hào)未鎖定.@Overridepublic boolean isAccountNonLocked() {return true;}// true: 憑證未過期.@Overridepublic boolean isCredentialsNonExpired() {return true;}// true: 賬號(hào)可用.@Overridepublic boolean isEnabled() {return true;}// 返回用戶權(quán)限//我們有兩種用戶:1代表管理員,2代表普通用戶@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {List<GrantedAuthority> list = new ArrayList<>();list.add(new GrantedAuthority() {@Overridepublic String getAuthority() {switch (type) {case 1:return "ADMIN";default:return "USER";}}});return list;}}

著重介紹一下getAuthorities方法:

它的返回值是一個(gè)權(quán)限集合,因?yàn)槲覀冋鎸?shí)開發(fā)可能是這樣的:

用戶表:記錄了用戶類型(是普通用戶還是1級(jí)管理員、2級(jí)管理員、賣家買家等等)

權(quán)限表:記錄了每個(gè)角色有什么權(quán)限,比如普通用戶可以發(fā)帖評(píng)論點(diǎn)贊,管理員可以刪貼置頂?shù)鹊取?/p>

最后我們通過用戶類型,查到多種權(quán)限,并且返回。

因?yàn)槊糠N用戶有多種權(quán)限,所以getAuthorities方法的返回值是一個(gè)權(quán)限集合。,這個(gè)集合可以裝很多GrantedAuthority對(duì)象。

本代碼的集合只裝了一個(gè)權(quán)限對(duì)象,并且重寫了對(duì)應(yīng)回去權(quán)限的方法。。


service層實(shí)現(xiàn)接口和對(duì)應(yīng)方法。

import com.nowcoder.community.dao.UserMapper; import com.nowcoder.community.entity.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;@Service public class UserService implements UserDetailsService {@Autowiredprivate UserMapper userMapper;public User findUserByName(String username) {return userMapper.selectByName(username);}@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {return this.findUserByName(username);} }

這個(gè)接口是要實(shí)現(xiàn)查找對(duì)應(yīng)的用戶。

我們自己寫登錄邏輯的時(shí)候,一樣要這么做:用賬號(hào)(id)查到用戶,讀取密碼,看看用戶輸入的和在數(shù)據(jù)庫(kù)查到的是否相同,

security底層也是做了類似的事情,所以我們需要告訴他如何查找用戶。

如果我們之前寫過selectByName之類的方法,可以直接調(diào)用即可。

這里我把dao層和xml實(shí)現(xiàn)也給出來。

import com.nowcoder.community.entity.User; import org.apache.ibatis.annotations.Mapper;@Mapper public interface UserMapper {User selectByName(String username); } <mapper namespace="com.community.dao.UserMapper"><sql id="selectFields">id, username, password, salt, email, type, status, activation_code, header_url, create_time</sql><select id="selectByName" resultType="User">select<include refid="selectFields"></include>from userwhere username = #{username}</select></mapper>

核心操作

書寫配置類統(tǒng)一管理。

有詳細(xì)的注釋。

通常我們需要書寫如下代碼:

忽略哪些資源?

認(rèn)證

授權(quán)

package com.community.config;import com.community.entity.User; import com.community.service.UserService; import com.community.util.CommunityUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import org.springframework.security.web.authentication.rememberme.InMemoryTokenRepositoryImpl;import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException;@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserService userService;@Overridepublic void configure(WebSecurity web) throws Exception {// 忽略靜態(tài)資源的訪問web.ignoring().antMatchers("/resources/**");}// AuthenticationManager: 認(rèn)證的核心接口.// AuthenticationManagerBuilder: 用于構(gòu)建AuthenticationManager對(duì)象的工具.// ProviderManager: AuthenticationManager接口的默認(rèn)實(shí)現(xiàn)類.@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {// 內(nèi)置的認(rèn)證規(guī)則// auth.userDetailsService(userService).passwordEncoder(new Pbkdf2PasswordEncoder("12345"));// 自定義認(rèn)證規(guī)則// AuthenticationProvider: ProviderManager持有一組AuthenticationProvider,每個(gè)AuthenticationProvider負(fù)責(zé)一種認(rèn)證.// 委托模式: ProviderManager將認(rèn)證委托給AuthenticationProvider.auth.authenticationProvider(new AuthenticationProvider() {// Authentication: 用于封裝認(rèn)證信息的接口,不同的實(shí)現(xiàn)類代表不同類型的認(rèn)證信息.@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {String username = authentication.getName();String password = (String) authentication.getCredentials();User user = userService.findUserByName(username);if (user == null) {throw new UsernameNotFoundException("賬號(hào)不存在!");}password = CommunityUtil.md5(password + user.getSalt());if (!user.getPassword().equals(password)) {throw new BadCredentialsException("密碼不正確!");}// principal: 主要信息; credentials: 證書; authorities: 權(quán)限;return new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());}// 當(dāng)前的AuthenticationProvider支持哪種類型的認(rèn)證.@Overridepublic boolean supports(Class<?> aClass) {// UsernamePasswordAuthenticationToken: Authentication接口的常用的實(shí)現(xiàn)類.return UsernamePasswordAuthenticationToken.class.equals(aClass);}});}@Overrideprotected void configure(HttpSecurity http) throws Exception {// 登錄相關(guān)配置http.formLogin().loginPage("/loginpage").loginProcessingUrl("/login").successHandler(new AuthenticationSuccessHandler() {@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {response.sendRedirect(request.getContextPath() + "/index");}}).failureHandler(new AuthenticationFailureHandler() {@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {request.setAttribute("error", e.getMessage());request.getRequestDispatcher("/loginpage").forward(request, response);}});// 退出相關(guān)配置http.logout().logoutUrl("/logout").logoutSuccessHandler(new LogoutSuccessHandler() {@Overridepublic void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {response.sendRedirect(request.getContextPath() + "/index");}});// 授權(quán)配置http.authorizeRequests().antMatchers("/letter").hasAnyAuthority("USER", "ADMIN").antMatchers("/admin").hasAnyAuthority("ADMIN").and().exceptionHandling().accessDeniedPage("/denied");// 增加Filter,處理驗(yàn)證碼http.addFilterBefore(new Filter() {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;if (request.getServletPath().equals("/login")) {String verifyCode = request.getParameter("verifyCode");if (verifyCode == null || !verifyCode.equalsIgnoreCase("1234")) {request.setAttribute("error", "驗(yàn)證碼錯(cuò)誤!");request.getRequestDispatcher("/loginpage").forward(request, response);return;}}// 讓請(qǐng)求繼續(xù)向下執(zhí)行.filterChain.doFilter(request, response);}}, UsernamePasswordAuthenticationFilter.class);// 記住我http.rememberMe().tokenRepository(new InMemoryTokenRepositoryImpl()).tokenValiditySeconds(3600 * 24).userDetailsService(userService);} }

表單

<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head><meta charset="UTF-8"><title>登錄</title> </head> <body><h1>登錄社區(qū)</h1><form method="post" th:action="@{/login}"><p style="color:red;" th:text="${error}"><!--提示信息--></p><p>賬號(hào):<input type="text" name="username" th:value="${param.username}"></p><p>密碼:<input type="password" name="password" th:value="${param.password}"></p><p>驗(yàn)證碼:<input type="text" name="verifyCode"> <i>1234</i></p><p><input type="checkbox" name="remember-me"> 記住我</p><p><input type="submit" value="登錄"></p></form></body> </html>

HomeController?

package com.nowcoder.community.controller;import com.nowcoder.community.entity.User; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod;@Controller public class HomeController {@RequestMapping(path = "/index", method = RequestMethod.GET)public String getIndexPage(Model model) {// 認(rèn)證成功后,結(jié)果會(huì)通過SecurityContextHolder存入SecurityContext中.Object obj = SecurityContextHolder.getContext().getAuthentication().getPrincipal();if (obj instanceof User) {model.addAttribute("loginUser", obj);}return "/index";}@RequestMapping(path = "/discuss", method = RequestMethod.GET)public String getDiscussPage() {return "/site/discuss";}@RequestMapping(path = "/letter", method = RequestMethod.GET)public String getLetterPage() {return "/site/letter";}@RequestMapping(path = "/admin", method = RequestMethod.GET)public String getAdminPage() {return "/site/admin";}@RequestMapping(path = "/loginpage", method = {RequestMethod.GET, RequestMethod.POST})public String getLoginPage() {return "/site/login";}// 拒絕訪問時(shí)的提示頁(yè)面@RequestMapping(path = "/denied", method = RequestMethod.GET)public String getDeniedPage() {return "/error/404";}}

?

?

總結(jié)

以上是生活随笔為你收集整理的Spring Security使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。