亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > Java > 正文

SpringBoot+SpringSecurity處理Ajax登錄請求問題(推薦)

2024-07-13 10:15:02
字體:
來源:轉載
供稿:網友

最近在項目中遇到了這樣一個問題:前后端分離,前端用Vue來做,所有的數據請求都使用vue-resource,沒有使用表單,因此數據交互都是使用JSON,后臺使用Spring Boot,權限驗證使用了Spring Security,因為之前用Spring Security都是處理頁面的,這次單純處理Ajax請求,因此記錄下遇到的一些問題。這里的解決方案不僅適用于Ajax請求,也可以解決移動端請求驗證。

創建工程

首先我們需要創建一個Spring Boot工程,創建時需要引入Web、Spring Security、MySQL和MyBatis(數據庫框架其實隨意,我這里使用MyBatis),創建好之后,依賴文件如下:

<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.1</version></dependency><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><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope></dependency><dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.11</version></dependency>

注意最后一個 commons-codec 依賴是我手動加入進來的,這是一個Apache的開源項目,可以用來生成MD5消息摘要,我在后文中將對密碼進行簡單的處理。

創建數據庫并配置

為了簡化邏輯,我這里創建了三個表,分別是用戶表、角色表、用戶角色關聯表,如下:

springboot,springsecurity,ajax,ajax登錄請求

接下來我們需要在application.properties中對自己的數據庫進行簡單的配置,這里各位小伙伴視自己的具體情況而定。

spring.datasource.url=jdbc:mysql:///vueblogspring.datasource.username=rootspring.datasource.password=123

構造實體類

這里主要是指構造用戶類,這里的用戶類比較特殊,必須實現UserDetails接口,如下:

public class User implements UserDetails { private Long id; private String username; private String password; private String nickname; private boolean enabled; private List<Role> roles; @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return enabled; } @Override public List<GrantedAuthority> getAuthorities() { List<GrantedAuthority> authorities = new ArrayList<>(); for (Role role : roles) {  authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName())); } return authorities; } //getter/setter省略...}

實現了UserDetails接口之后,該接口中有幾個方法需要我們實現,四個返回Boolean的方法都是見名知意,enabled表示檔期賬戶是否啟用,這個我數據庫中確實有該字段,因此根據查詢結果返回,其他的為了簡單期間都直接返回true,getAuthorities方法返回當前用戶的角色信息,用戶的角色其實就是roles中的數據,將roles中的數據轉換為List<GrantedAuthority>之后返回即可, 這里有一個要注意的地方,由于我在數據庫中存儲的角色名都是諸如‘超級管理員'、‘普通用戶'之類的,并不是以 ROLE_ 這樣的字符開始的,因此需要在這里手動加上 ROLE_ ,切記 。

另外還有一個Role實體類,比較簡單,按照數據庫的字段創建即可,這里不再贅述。

創建UserService

這里的UserService也比較特殊,需要實現UserDetailsService接口,如下:

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

實現了UserDetailsService接口之后,我們需要實現該接口中的loadUserByUsername方法,即根據用戶名查詢用戶。這里注入了兩個MyBatis中的Mapper,UserMapper用來查詢用戶,RolesMapper用來查詢角色。在loadUserByUsername方法中,首先根據傳入的參數(參數就是用戶登錄時輸入的用戶名)去查詢用戶,如果查到的用戶為null,可以直接拋一個UsernameNotFoundException異常,但是我為了處理方便,返回了一個沒有任何值的User對象,這樣在后面的密碼比對過程中一樣會發現登錄失敗的(這里大家根據自己的業務需求調整即可),如果查到的用戶不為null,此時我們根據查到的用戶id再去查詢該用戶的角色,并將查詢結果放入到user對象中,這個查詢結果將在user對象的getAuthorities方法中用上。

Security配置

我們先來看一下我的Security配置,然后我再來一一解釋:

@Configurationpublic class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired UserService userService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception {  auth.userDetailsService(userService).passwordEncoder(new PasswordEncoder() {   @Override   public String encode(CharSequence charSequence) {    return DigestUtils.md5DigestAsHex(charSequence.toString().getBytes());   }   /**    * @param charSequence 明文    * @param s 密文    * @return    */   @Override   public boolean matches(CharSequence charSequence, String s) {    return s.equals(DigestUtils.md5DigestAsHex(charSequence.toString().getBytes()));   }  }); } @Override protected void configure(HttpSecurity http) throws Exception {  http.authorizeRequests()    .antMatchers("/admin/**").hasRole("超級管理員")    .anyRequest().authenticated()//其他的路徑都是登錄后即可訪問    .and().formLogin().loginPage("/login_page").successHandler(new AuthenticationSuccessHandler() {   @Override   public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {    httpServletResponse.setContentType("application/json;charset=utf-8");    PrintWriter out = httpServletResponse.getWriter();    out.write("{/"status/":/"ok/",/"msg/":/"登錄成功/"}");    out.flush();    out.close();   }  })    .failureHandler(new AuthenticationFailureHandler() {     @Override     public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {      httpServletResponse.setContentType("application/json;charset=utf-8");      PrintWriter out = httpServletResponse.getWriter();      out.write("{/"status/":/"error/",/"msg/":/"登錄失敗/"}");      out.flush();      out.close();     }    }).loginProcessingUrl("/login")    .usernameParameter("username").passwordParameter("password").permitAll()    .and().logout().permitAll().and().csrf().disable(); } @Override public void configure(WebSecurity web) throws Exception {  web.ignoring().antMatchers("/reg"); }}

這是我們配置的核心,小伙伴們聽我一一道來:

1.首先這是一個配置類,因此記得加上@Configuration注解,又因為這是Spring Security的配置,因此記得繼承WebSecurityConfigurerAdapter。

2.將剛剛創建好的UserService注入進來,一會我們要用。

3.configure(AuthenticationManagerBuilder auth)方法中用來配置我們的認證方式,在auth.userDetailsService()方法中傳入userService,這樣userService中的loadUserByUsername方法在用戶登錄時將會被自動調用。后面的passwordEncoder是可選項,可寫可不寫,因為我是將用戶的明文密碼生成了MD5消息摘要后存入數據庫的,因此在登錄時也需要對明文密碼進行處理,所以就加上了passwordEncoder,加上passwordEncoder后,直接new一個PasswordEncoder匿名內部類即可,這里有兩個方法要實現,看名字就知道方法的含義,第一個方法encode顯然是對明文進行加密,這里我使用了MD5消息摘要,具體的實現方法是由commons-codec依賴提供的;第二個方法matches是密碼的比對,兩個參數,第一個參數是明文密碼,第二個是密文,這里只需要對明文加密后和密文比較即可(小伙伴如果對此感興趣可以繼續考慮密碼加鹽)。

4.configure(HttpSecurity http)用來配置我們的認證規則等,authorizeRequests方法表示開啟了認證規則配置,antMatchers("/admin/**").hasRole("超級管理員")表示 /admin/** 的路徑需要有‘超級管理員'角色的用戶才能訪問,我在網上看到小伙伴對hasRole方法中要不要加 ROLE_ 前綴有疑問,這里是不要加的,如果用hasAuthority方法才需要加。anyRequest().authenticated()表示其他所有路徑都是需要認證/登錄后才能訪問。接下來我們配置了登錄頁面為login_page,登錄處理路徑為/login,登錄用戶名為username,密碼為password,并配置了這些路徑都可以直接訪問,注銷登陸也可以直接訪問,最后關閉csrf。在successHandler中,使用response返回登錄成功的json即可,切記不可以使用defaultSuccessUrl,defaultSuccessUrl是只登錄成功后重定向的頁面,使用failureHandler也是由于相同的原因。

5.configure(WebSecurity web)方法中我配置了一些過濾規則,不贅述。

6.另外,對于靜態文件,如 /images/**/css/** 、 /js/** 這些路徑,這里默認都是不攔截的。

Controller

最后來看看我們的Controller,如下:

@RestControllerpublic class LoginRegController { /**  * 如果自動跳轉到這個頁面,說明用戶未登錄,返回相應的提示即可  * <p>  * 如果要支持表單登錄,可以在這個方法中判斷請求的類型,進而決定返回JSON還是HTML頁面  *  * @return  */ @RequestMapping("/login_page") public RespBean loginPage() {  return new RespBean("error", "尚未登錄,請登錄!"); }}

這個Controller整體來說還是比較簡單的,RespBean一個響應bean,返回一段簡單的json,不贅述,這里需要小伙伴注意的是 login_page ,我們配置的登錄頁面是一個 login_page ,但實際上 login_page 并不是一個頁面,而是返回一段JSON,這是因為當我未登錄就去訪問其他頁面時Spring Security會自動跳轉到到 login_page 頁面,但是在Ajax請求中,不需要這種跳轉,我要的只是是否登錄的提示,所以這里返回json即可。

測試

最后小伙伴可以使用POSTMAN或者RESTClient等工具來測試登錄和權限問題,我就不演示了。

Ok,經過上文的介紹,想必小伙伴們對Spring Boot+Spring Security處理Ajax登錄請求已經有所了解了,好了,本文就說到這里,有問題歡迎留言討論。


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美人交a欧美精品| 91网在线免费观看| 亚洲四色影视在线观看| 国产精品视频久| 久久久亚洲国产| 欧美性极品少妇精品网站| 性欧美在线看片a免费观看| 国产人妖伪娘一区91| 日韩av免费一区| 亚洲欧洲成视频免费观看| 欧美极品少妇xxxxⅹ喷水| 中文字幕在线看视频国产欧美在线看完整| 久久免费成人精品视频| 亚洲日韩第一页| 亚洲美女性生活视频| 亚洲欧美日韩区| 久久久久久久av| 亚洲淫片在线视频| 日韩在线中文视频| 夜夜嗨av一区二区三区四区| 日韩欧美国产视频| 欧美理论片在线观看| 成人中文字幕+乱码+中文字幕| 亚洲天堂免费视频| 欧美性猛交xxxx免费看漫画| 中文字幕亚洲无线码a| 欧美日韩国产999| 一色桃子一区二区| 亚洲天堂成人在线| 欧美日韩综合视频网址| 国产精品人成电影| 久久中文精品视频| 亚洲成av人乱码色午夜| 亚洲综合日韩中文字幕v在线| 欧美亚洲国产日韩2020| 欧美影院在线播放| 国产精品白嫩初高中害羞小美女| 亚洲国产精品电影在线观看| www.日韩不卡电影av| 亚洲一区二区三区在线免费观看| 国产三级精品网站| 久久人人看视频| 一区二区三区视频免费在线观看| 欧美成人午夜剧场免费观看| 国产精品激情av在线播放| 日韩精品一二三四区| 亚洲最新av在线| 亚洲在线一区二区| 欧美理论电影在线观看| 欧美另类暴力丝袜| 亚洲欧洲中文天堂| 欧美在线日韩在线| 亚洲女人天堂成人av在线| 日韩成人在线视频观看| 国产精品美女www| 国产91在线播放精品91| 91人人爽人人爽人人精88v| 国产日韩在线看片| 日韩欧美国产骚| 成人国产在线激情| 国产精品久久久久久久美男| 麻豆国产va免费精品高清在线| 欧美日韩综合视频网址| 国语自产精品视频在免费| 亚洲精品乱码久久久久久按摩观| 超碰97人人做人人爱少妇| www.亚洲免费视频| 国产精自产拍久久久久久蜜| 日韩在线视频一区| 日韩在线中文字| 欧美日韩爱爱视频| 日韩成人在线观看| 午夜精品久久久久久久白皮肤| 日韩精品极品视频| 青青草99啪国产免费| 久久久久久美女| 日本精品久久久久影院| 欧美亚洲免费电影| 日韩电影中文字幕| 日韩久久免费电影| 亚洲视频综合网| 国产精品video| 91网站免费看| 91精品久久久久久久久久久| 国产成人综合精品在线| 日韩av免费在线播放| 97免费中文视频在线观看| 欧美中文字幕精品| 亚洲精品在线视频| 久久综合五月天| 国产精品高潮呻吟久久av黑人| 久久久久久久激情视频| 日本精品一区二区三区在线播放视频| 欧美日韩国产一区在线| 亚洲欧洲在线视频| 亚洲国产精品久久精品怡红院| 亚洲精品久久久久久久久久久久| 欧美成人小视频| 久久久久国产一区二区三区| 亚洲福利视频在线| 国产久一一精品| 精品国模在线视频| 亚洲精品小视频在线观看| 国产精品av在线播放| 色偷偷88888欧美精品久久久| 色偷偷偷亚洲综合网另类| 日本成人免费在线| 91久久精品日日躁夜夜躁国产| 97久久精品国产| 欧亚精品中文字幕| 中文字幕精品影院| 欧美午夜宅男影院在线观看| 国产综合福利在线| 久久99精品国产99久久6尤物| 国产精品影院在线观看| 久久成人精品电影| 精品久久久久久久中文字幕| 欧美成年人视频| 亚洲高清不卡av| 96精品视频在线| 日韩av免费在线观看| 在线日韩中文字幕| 久久精品99国产精品酒店日本| 久久久久国色av免费观看性色| 在线精品91av| 国产色综合天天综合网| 亚洲有声小说3d| 亚洲美女中文字幕| 少妇av一区二区三区| 中文.日本.精品| 欧美极品美女视频网站在线观看免费| 91精品久久久久久久久久久| 久久精品视频播放| 亚洲精品videossex少妇| 人体精品一二三区| 成人国产亚洲精品a区天堂华泰| 国产91在线视频| 久久精品电影网站| 国产精品video| 久久久精品2019中文字幕神马| 亚洲理论片在线观看| 爽爽爽爽爽爽爽成人免费观看| 亚洲美女性视频| 中文字幕亚洲无线码在线一区| 成人国产亚洲精品a区天堂华泰| 日韩欧美在线免费| 亚洲成人网在线| 国产中文日韩欧美| 亚洲小视频在线观看| 色综合影院在线| 亚洲午夜未删减在线观看| 日韩精品高清在线| 国产精品永久在线| 日韩精品视频免费专区在线播放| 韩国三级日本三级少妇99| 国产美女被下药99| 亚洲欧美在线一区| 欧美日韩国产色视频| 日韩欧美国产一区二区| 日韩美女在线看| 欧美一级高清免费| 国产成人精品久久二区二区| 日韩一区二区欧美| 成人日韩av在线|