目录
------------------------------------
1. 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2. jackson(spring boot包下的)
//jackson 将map对象转换为json对象 spring-boot-starter-web //pw.println("{\"status\":200,\"msg\":\"ok\"}");
package com.cy.jt.security.config.handler;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
public class JsonAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication)
throws IOException, ServletException {
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
PrintWriter pw= response.getWriter();
Map<String,Object> map=new HashMap<>();
map.put("state", 200);
map.put("msg", "Login ok");
//jackson 将map对象转换为json对象 spring-boot-starter-web
//pw.println("{\"status\":200,\"msg\":\"ok\"}");
String jsonStr = new ObjectMapper().writeValueAsString(map);
pw.println(jsonStr);
pw.flush();
}
}
3. yml基本不写 使用SecurityConfig
4. 自定义登录逻辑
-> 4.1 在配置类中
@Bean
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
配置类信息
package com.cy.jt.security.config;
import com.cy.jt.security.config.handler.JsonAuthenticationSuccessHandler;
import com.cy.jt.security.config.handler.RedirectAuthenticationSuccessHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.server.authentication.RedirectServerAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
//配置类 启动就会优先加载 @configuration 通常会对第三方资源进行整合
/**
* 资源放行 还是在配置类中添加放行条件 和成功失败返回情况
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// 对http请求的安全控制进行配置
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();//1.关闭跨域攻击
//自定义登录页面
http.formLogin()
.loginPage("/login.html")//2.设置登录url(静态页面)
.loginProcessingUrl("/login")//地址对应的处理器 与页面action相同
// .usernameParameter("username")
// .passwordParameter("password") 与前端不相同就添加属性
//.successForwardUrl("/index.html");//get请求 会405的
//.successForwardUrl("/index");//get请求 写个controller接收可以获取到请求的用户名
// .defaultSuccessUrl("/index.html")//默认请求成功路径 默认转发
.failureUrl("https://www.baidu.com") //默认....error 跳回原页面
.successHandler(
//new RedirectAuthenticationSuccessHandler("/index.html"));
new JsonAuthenticationSuccessHandler());
//3. 放行登录url 不用认证,其他认证
http.authorizeRequests()
.antMatchers("/login.html","/images/**")
.permitAll()//允许访问上面的
.anyRequest().authenticated();//其他任何请求都需要认证
}
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
--> 自定义登录(连接数据库)模拟数据库
package com.cy.jt.security.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 自定义登录逻辑 UserDetailsService需要实现
*/
@Service
public class UserDetailServiceImpl implements UserDetailsService {
@Autowired
private BCryptPasswordEncoder passwordEncoder;
//分配权限方式是 角色 使用 ROLE_ 做前缀
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
//userMapper.selectUSerByUsername(username)
if(!"pzy".equals(username))
throw new UsernameNotFoundException("user not exists");
//从数据库查看权限信息
List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList(
"ROLE_jinpai,ROLE_tongpai,sys:res:retrieve,sys:res:create"
);
String encodePwd =passwordEncoder.encode("123456");
//import org.springframework.security.core.userdetails.User;
User user=new User(username, encodePwd, authorities);
return user;
}
}
------------------ 登录成功处理器 AuthenticationSuccessHandler 登录失败处理器 AuthenticationFailureHandler
需要继承的 然后重新编写配置类SecurityConfig
.failureHandler (new AuthenticationFailureHandler) .successHandler (new AuthenticationSuccessHandler)
-----------------------------------------
authentication对象
User principal =(User) authentication.getPrincipal();//继承userDetails System.out.println( principal.getUsername());//获取权限用户名 System.out.println(principal.getPassword()); System.out.println(principal.getAuthorities()); Object credentials = authentication.getCredentials();//获取密码 System.out.println(principal); System.out.println(credentials);
-------------------------------------------------------
权限控制
--------------> 最开始 启动类家伙加上@EnableGlobalMethodSecurity(prePostEnabled = true)
在每个方法上添加
//@PreAuthorize("hasRole('normal')") @PreAuthorize("hasAuthority('sys:res:retrieve')")
403 没权限 401 没认证 通常报错信息
-------------------------
直接报错吧不好 需要自定义异常处理机制
没认证失败处理器 401
package com.cy.jt.security.config.handler;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
/**
* 401认证异常
* 假如用户没有认证 就去访问需要认证才能访问的资源 系统
* 底层会抛出异常 AuthenticationException
* 系统默认对此异常的处理方式是跳转到登录页面
*/
public class DefaultAuthenticationEntryPoint implements AuthenticationEntryPoint {
/**
*
* @param request
* @param response
* @param authException
* @throws IOException
* @throws ServletException
*/
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException)
throws IOException, ServletException {
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
PrintWriter pw = response.getWriter();
Map<String,Object> map=new HashMap<>();
map.put("status", HttpServletResponse.SC_UNAUTHORIZED);//403
map.put("message", "请先认证后, 在登录重试!!!");
String jsonStr = new ObjectMapper().writeValueAsString(map);
pw.println(jsonStr);
pw.flush();
}
}
认证权限失败处理器 403
package com.cy.jt.security.config.handler;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
/**
* 默认的用于处理访问被拒绝的异常处理器对象
* denied 拒绝
*/
public class DefaultAccessDeniedException implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request,
HttpServletResponse response,
AccessDeniedException accessDeniedException)
throws IOException, ServletException {
// response.sendRedirect("https://www.baidu.com");
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
PrintWriter pw = response.getWriter();
Map<String,Object> map=new HashMap<>();
map.put("status", HttpServletResponse.SC_FORBIDDEN);//403
map.put("message", "没有权限, 请升级权限!!!");
String jsonStr = new ObjectMapper().writeValueAsString(map);
pw.println(jsonStr);
pw.flush();
}
}