超全的springboot+springsecurity實現前后端分離簡單實現!
點擊上方藍色字體,選擇“標星公眾號”
優(yōu)質文章,第一時間送達
1、前言部分
1.1、嘮嗑部分(如何學習?)
1.2、技術支持
1.3、預期實現效果圖
?2、核心部分
2.1、springsecurity原理解釋:
2.2、踩坑集錦
訪問/login時必須要用post方法!, 訪問的參數名必須為username和password ??
訪問/logout時即可用post也可用get方法!
//springsecurity配置文件中的hasRole("")不能以ROLE開頭,比如ROLE_USER就是錯的,springsecurity會默認幫我們加上,但數據庫的權限字段必須是ROLE_開頭,否則讀取不到
?
2.3、代碼部分
?
????????
????????
????????????com.google.code.gson
????????????gson
????????????2.8.2
????????
????????
????????
????????????org.springframework.boot
????????????spring-boot-starter-web
????????
????????
????????
????????????org.springframework.boot
????????????spring-boot-starter-security
????????
????????
????????
????????????mysql
????????????mysql-connector-java
????????????runtime
????????
????????
????????
????????????org.projectlombok
????????????lombok
????????????true
????????
????????
????????
????????????com.baomidou
????????????mybatis-plus-boot-starter
????????????3.4.1
????????
??????
????????
????????
????????????org.springframework.boot
????????????spring-boot-starter-test
????????????test
????????????
????????????????
????????????????????org.junit.vintage
????????????????????junit-vintage-engine
????????????????
????????????
????????
????????
????????
????????????org.springframework.security
????????????spring-security-config
????????????5.3.4.RELEASE
????????
????????
????????????org.springframework.security
????????????spring-security-web
????????????5.3.4.RELEASE
????????
????
@Data
@NoArgsConstructor
@AllArgsConstructor
public?class?Msg?{
????int?code;???//錯誤碼
????String?Message;?//消息提示
????Map?data=new?HashMap ();???//數據
?
????//無權訪問
????public?static?Msg?denyAccess(String?message){
????????Msg?result=new?Msg();
????????result.setCode(300);
????????result.setMessage(message);
????????return?result;
????}
?
????//操作成功
????public?static?Msg?success(String?message){
????????Msg?result=new?Msg();
????????result.setCode(200);
????????result.setMessage(message);
????????return?result;
????}
?
????//客戶端操作失敗
????public?static?Msg?fail(String?message){
????????Msg?result=new?Msg();
????????result.setCode(400);
????????result.setMessage(message);
????????return?result;
????}
?
????public?Msg?add(String?key,Object?value){
????????this.data.put(key,value);
????????return?this;
????}
}
@Data
public?class?User?implements?Serializable?{
?
????private?Integer?id;?????
?
????private?String?account;
?
????private?String?password;
?
????private?String?role;
????
}
@Repository
public?interface?UserMapper?extends?BaseMapper?{
?
}
public?interface?UserService{
?
}
@Service
public?class?UserServiceImpl?extends?ServiceImpl?implements?UserService,UserDetailsService?{
?
????@Autowired
????UserMapper?userMapper;
?
????//加載用戶
????@Override
????public?UserDetails?loadUserByUsername(String?s)?throws?UsernameNotFoundException?{
????????//mybatis-plus幫我們寫好了sql語句,相當于?select?*?from?user?where?account?='${account}'
????????QueryWrapper?wrapper=new?QueryWrapper<>();
????????wrapper.eq("account",s);
????????User?user=userMapper.selectOne(wrapper);????//user即為查詢結果
????????if(user==null){
????????????throw?new?UsernameNotFoundException("用戶名錯誤!!");
????????}
?
????????//獲取用戶權限,并把其添加到GrantedAuthority中
????????List?grantedAuthorities=new?ArrayList<>();
????????GrantedAuthority?grantedAuthority=new?SimpleGrantedAuthority(user.getRole());
????????grantedAuthorities.add(grantedAuthority);
?
????????//方法的返回值要求返回UserDetails這個數據類型,??UserDetails是接口,找它的實現類就好了
????????//new?org.springframework.security.core.userdetails.User(String?username,String?password,Collection?extends?GrantedAuthority>?authorities)?就是它的實現類
????????return?new?org.springframework.security.core.userdetails.User(s,user.getPassword(),grantedAuthorities);
????}
}
@RestController
public?class?UserController?{
????@GetMapping("index")
????public?String?index(){
????????return?"index";
????}
?
????@GetMapping("hello")
????public?String?hello(){
????????return?"hello";
????}
}
@Component
public?class?AuthenticationEnryPoint?implements?AuthenticationEntryPoint?{
?
????@Autowired
????Gson?gson;
?
????//未登錄時返回給前端數據
????@Override
????public?void?commence(HttpServletRequest?request,?HttpServletResponse?response,?AuthenticationException?e)?throws?IOException,?ServletException?{
????????Msg?result=Msg.fail("需要登錄!!");
????????response.setContentType("application/json;charset=utf-8");
????????response.getWriter().write(gson.toJson(result));
????}
}
//登錄失敗返回給前端消息
@Component
public?class?AuthenticationFailure?implements?AuthenticationFailureHandler{
????@Autowired
????Gson?gson;
?
????@Override
????public?void?onAuthenticationFailure(HttpServletRequest?request,?HttpServletResponse?response,?AuthenticationException?e)?throws?IOException,?ServletException?{
????????Msg?msg=null;
????????if(e?instanceof?UsernameNotFoundException){
????????????msg=Msg.fail(e.getMessage());
????????}else?if(e?instanceof?BadCredentialsException){
????????????msg=Msg.fail("密碼錯誤!!");
????????}else?{
????????????msg=Msg.fail(e.getMessage());
????????}
????????//處理編碼方式,防止中文亂碼的情況
????????response.setContentType("text/json;charset=utf-8");
????????//返回給前臺
????????response.getWriter().write(gson.toJson(msg));
????}
}
@Component
public?class?AuthenticationSuccess?implements?AuthenticationSuccessHandler{
????@Autowired
????Gson?gson;
?
????@Override
????public?void?onAuthenticationSuccess(HttpServletRequest?request,?HttpServletResponse?response,?Authentication?authentication)?throws?IOException,?ServletException?{
????????//登錄成功時返回給前端的數據
????????Msg?result=Msg.success("登錄成功?。。。?!");
????????response.setContentType("application/json;charset=utf-8");
????????response.getWriter().write(gson.toJson(result));
????}
}
@Component
public?class?AuthenticationLogout?implements?LogoutSuccessHandler{
????@Autowired
????Gson?gson;
?
????@Override
????public?void?onLogoutSuccess(HttpServletRequest?request,?HttpServletResponse?response,?Authentication?authentication)?throws?IOException,?ServletException?{
????????Msg?result=Msg.success("注銷成功");
????????response.setContentType("application/json;charset=utf-8");
????????response.getWriter().write(gson.toJson(result));
????}
}
//無權訪問
@Component
public?class?AccessDeny?implements?AccessDeniedHandler{
????@Autowired
????Gson?gson;
?
????@Override
????public?void?handle(HttpServletRequest?request,?HttpServletResponse?response,?AccessDeniedException?e)?throws?IOException,?ServletException?{
????????Msg?result=?Msg.denyAccess("無權訪問,need?Authorities!!");
????????response.setContentType("application/json;charset=utf-8");
????????response.getWriter().write(gson.toJson(result));
????}
}
@Component
public?class?SessionInformationExpiredStrategy?implements?org.springframework.security.web.session.SessionInformationExpiredStrategy{
????@Autowired
????Gson?gson;
?
????@Override
????public?void?onExpiredSessionDetected(SessionInformationExpiredEvent?event)?throws?IOException,?ServletException?{
????????Msg?result=?Msg.fail("您的賬號在異地登錄,建議修改密碼");
????????HttpServletResponse?response=event.getResponse();
????????response.setContentType("application/json;charset=utf-8");
????????response.getWriter().write(gson.toJson(result));
????}
}
@Component
public?class?SelfAuthenticationProvider?implements?AuthenticationProvider{
????@Autowired
????UserServiceImpl?userServiceImpl;
?
????@Autowired
????BCryptPasswordEncoder?bCryptPasswordEncoder;
?
????@Override
????public?Authentication?authenticate(Authentication?authentication)?throws?AuthenticationException?{
????????String?account=?authentication.getName();?????//獲取用戶名
????????String?password=?(String)?authentication.getCredentials();??//獲取密碼
????????UserDetails?userDetails=?userServiceImpl.loadUserByUsername(account);
????????boolean?checkPassword=?bCryptPasswordEncoder.matches(password,userDetails.getPassword());
????????if(!checkPassword){
????????????throw?new?BadCredentialsException("密碼不正確,請重新登錄!");
????????}
????????return?new?UsernamePasswordAuthenticationToken(account,password,userDetails.getAuthorities());
????}
?
????@Override
????public?boolean?supports(Class>?aClass)?{
????????return?true;
????}
}
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled?=?true)?//開啟權限注解,默認是關閉的
public?class?SpringsecurityConfig?extends?WebSecurityConfigurerAdapter?{
?
????@Autowired
????AuthenticationEnryPoint?authenticationEnryPoint;????//未登錄
????@Autowired
????AuthenticationSuccess?authenticationSuccess;????//登錄成功
????@Autowired
????AuthenticationFailure?authenticationFailure;????//登錄失敗
????@Autowired
????AuthenticationLogout?authenticationLogout;??????//注銷
????@Autowired
????AccessDeny?accessDeny;??????//無權訪問
????@Autowired
????SessionInformationExpiredStrategy?sessionInformationExpiredStrategy;????//檢測異地登錄
????@Autowired
????SelfAuthenticationProvider?selfAuthenticationProvider;??????//自定義認證邏輯處理
?
????@Bean
????public?UserDetailsService?userDetailsService()?{
????????return?new?UserServiceImpl();
????}
?
????//加密方式
????@Bean
????public?BCryptPasswordEncoder?bCryptPasswordEncoder()?{
????????return?new?BCryptPasswordEncoder();
????}
?
????//認證
????@Override
????protected?void?configure(AuthenticationManagerBuilder?auth)?throws?Exception?{
????????auth.authenticationProvider(selfAuthenticationProvider);
????}
?
????//授權
????@Override
????protected?void?configure(HttpSecurity?http)?throws?Exception?{
????????//cors()解決跨域問題,csrf()會與restful風格沖突,默認springsecurity是開啟的,所以要disable()關閉一下
????????http.cors().and().csrf().disable();?????
????????
????????//?????/index需要權限為ROLE_USER才能訪問???/hello需要權限為ROLE_ADMIN才能訪問
????????http.authorizeRequests()
????????????????.antMatchers("/index").hasRole("USER")
????????????????.antMatchers("/hello").hasRole("ADMIN")
?
????????????????
????????????????.and()
????????????????.formLogin()??//開啟登錄
????????????????.permitAll()??//允許所有人訪問
????????????????.successHandler(authenticationSuccess)?//?登錄成功邏輯處理
????????????????.failureHandler(authenticationFailure)?//?登錄失敗邏輯處理
?
????????????????.and()
????????????????.logout()???//開啟注銷
????????????????.permitAll()????//允許所有人訪問
????????????????.logoutSuccessHandler(authenticationLogout)?//注銷邏輯處理
????????????????.deleteCookies("JSESSIONID")????//刪除cookie
?
????????????????.and().exceptionHandling()??
????????????????.accessDeniedHandler(accessDeny)????//權限不足的時候的邏輯處理
????????????????.authenticationEntryPoint(authenticationEnryPoint)??//未登錄是的邏輯處理
?
????????????????.and()
????????????????.sessionManagement()
????????????????.maximumSessions(1)?????//最多只能一個用戶登錄一個賬號
????????????????.expiredSessionStrategy(sessionInformationExpiredStrategy)??//異地登錄的邏輯處理
????????;
????}
}
server:
??port:?80
?
spring:
??datasource:
????url:?jdbc:mysql://localhost:3306/springsecurity_test?characterEncoding=utf8&serverTimezone=UTC
????username:?root
????password:?123456
????driver-class-name:?com.mysql.cj.jdbc.Driver
版權聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接:
https://blog.csdn.net/weixin_42375707/article/details/110678638
粉絲福利:Java從入門到入土學習路線圖
???

?長按上方微信二維碼?2 秒
感謝點贊支持下哈?
評論
圖片
表情














