Python 官方文档:入门教程 => 点击学习
目录本章内容思路方案怎么将字符串变成图片验证码?kaptcha这么玩hutool这么玩传统WEB项目过滤器方式认证器方式总结下前后端分离项目基于过滤器方式基于认证器方式本章内容 sp
spring security添加图片验证方式,在互联网上面有很多这种博客,都写的非常的详细了。本篇主要讲一些添加图片验证的思路。还有前后端分离方式,图片验证要怎么去处理?
小白: "我们从总体流程上看图片验证在认证的哪一个阶段?"
小黑: "在获取客户输入的用户名密码那一阶段,而且要在服务器获取数据库中用户名密码之前。这是一个区间[获取请求用户名密码, 获取数据库用户名密码)
而在 Spring security中, 可以很明显的发现有两种思路。
小白: "为什么是这个阶段呢? 不能是在判断密码验证之前呢?"
小黑: "你傻啊, 如果在你说的阶段, 服务器需要去数据库中获取用户信息, 这相当的浪费系统资源"
小白: "哦哦, 我错了, 让我屡屡整个流程应该是啥样"
小白: "我需要事先在后端生成一个验证码,然后通过验证码返回一张图片给前端。前端登录表单添加图片验证。用户输入图片验证后点击登录,会存放在request
请求中, 后端需要从request
请求中读取到图片验证,判断前后端验证码是否相同, 如果图片验证码相同之后才开始从数据库拿用户信息。否则直接抛出认证异常"
简单点: 数据库获取用户账户之前, 先进行图片验证码验证
这轮子肯定不能自己造, 有就拿来吧你
kaptcha
hutool
kaptcha
这么玩<!--验证码生成器-->
<dependency>
<groupId>com.GitHub.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
<exclusions>
<exclusion>
<artifactId>javax.servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
</exclusions>
</dependency>
@Bean
public DefaultKaptcha captchaProducer() {
Properties properties = new Properties();
properties.put("kaptcha.border", "no");
properties.put("kaptcha.textproducer.char.length","4");
properties.put("kaptcha.image.height","50");
properties.put("kaptcha.image.width","150");
properties.put("kaptcha.obscurificator.impl","com.Google.code.kaptcha.impl.ShadowGimpy");
properties.put("kaptcha.textproducer.font.color","black");
properties.put("kaptcha.textproducer.font.size","40");
properties.put("kaptcha.noise.impl","com.google.code.kaptcha.impl.NoNoise");
//properties.put("kaptcha.noise.impl","com.google.code.kaptcha.impl.DefaultNoise");
properties.put("kaptcha.textproducer.char.string","acdefhkmnprtwxy2345678");
DefaultKaptcha kaptcha = new DefaultKaptcha();
kaptcha.setConfig(new Config(properties));
return kaptcha;
}
@Resource
private DefaultKaptcha producer;
@GetMapping("/verify-code")
public void getVerifyCode(httpservletResponse response, HttpSession session) throws Exception {
response.setContentType("image/jpeg");
String text = producer.createText();
session.setAttribute("verify_code", text);
BufferedImage image = producer.createImage(text);
try (ServletOutputStream outputStream = response.getOutputStream()) {
ImageIO.write(image, "jpeg", outputStream);
}
}
hutool
这么玩@GetMapping("hutool-verify-code")
public void getHtoolVerifyCode(HttpServletResponse response, HttpSession session) throws IOException {
CircleCaptcha circleCaptcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 80);
session.setAttribute("hutool_verify_code", circleCaptcha.getCode());
response.setContentType(MediaType.IMAGE_PNG_VALUE);
circleCaptcha.write(response.getOutputStream());
}
这俩随便挑选一个完事
前端就非常简单了
<fORM th:action="@{/login}" method="post">
<div class="input">
<label for="name">用户名</label>
<input type="text" name="username" id="name">
<span class="spin"></span>
</div>
<div class="input">
<label for="pass">密码</label>
<input type="passWord" name="password" id="pass">
<span class="spin"></span>
</div>
<div class="input">
<label for="code">验证码</label>
<input type="text" name="code" id="code"><img src="/verify-code" alt="验证码">
<!--<input type="text" name="code" id="code"><img src="/hutool-verify-code" alt="验证码">-->
<span class="spin"></span>
</div>
<div class="button login">
<button type="submit">
<span>登录</span>
<i class="fa fa-check"></i>
</button>
</div>
<div th:text="${session.SPRING_SECURITY_LAST_EXCEPTION}"></div>
</form>
我们现在根据上面的思路来设计设计该怎么实现这项功能
@RequiredArgsConstructor
public class ValidateCodeFilter extends OncePerRequestFilter {
private final String login;
private static final AntPathRequestMatcher requiresAuthenticationRequestMatcher = new AntPathRequestMatcher(this.login,
"POST");
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (requiresAuthenticationRequestMatcher.matches(request)) {
validateCode(request);
}
filterChain.doFilter(request, response);
}
private void validateCode(HttpServletRequest request) {
HttpSession session = request.getSession();
// 获取保存在session中的code
String verifyCode = (String) session.getAttribute("verify_code");
if (StringUtils.isBlank(verifyCode)) {
throw new ValidateCodeException("请重新申请验证码!");
}
// 拿到前端的 code
String code = request.getParameter("code");
if (StringUtils.isBlank(code)) {
throw new ValidateCodeException("验证码不能为空!");
}
// 对比
if (!StringUtils.equalsIgnoreCase(code, verifyCode)) {
throw new AuthenticationServiceException("验证码错误!");
}
// 删除掉 session 中的 verify_code
session.removeAttribute("verify_code");
}
}
虽然OncePerRequestFilter
每次浏览器请求过来, 都会调用过滤器. 但是过滤器顺序是非常重要的
@Controller
@Slf4j
public class IndexController {
@GetMapping("login")
public String login() {
return "login";
}
@GetMapping("")
@ResponseBody
public Principal index(Principal principal) {
return principal;
}
}
@Configuration
public class SecurityConfig {
public static final String[] MATCHERS_URLS = {"/verify-code",
"/CSS
@Bean
public MyDaoAuthenticationProvider authenticationProvider() throws Exception {
MyDaoAuthenticationProvider authenticationProvider = new MyDaoAuthenticationProvider(Constants.LOGIN_USERNAME, Constants.LOGIN_PASSWORD);
authenticationProvider.setPasswordEncoder(passwordEncoder());
authenticationProvider.setUserDetailsService(inMemoryUserDetailsManager());
return authenticationProvider;
}
// 往子类AuthenticationManager里面添加的 authenticationProvider
httpSecurity.authenticationProvider(authenticationProvider());
小黑: "这上面的代码有问题, AuthenticationManger
有父类和子类, 上面这段代码同时往父类和子类都添加MyDaoAuthenticationProvider
, 这样MyDaoAuthenticationProvider
会被执行两次, 但request的流只能执行一次, 会报错"
小黑: "我们可以这么玩"
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// 代码省略
// 代码省略
// 代码省略
// 代码省略
// 往子类AuthenticationManager里面添加的 authenticationProvider, 但不能阻止 AuthenticationManger 父类加载 DaoAuthenticationProvider
AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
// 但是这种方式可以将 parent Manager 设置为 null, 所以是可以的
authenticationManagerBuilder.parentAuthenticationManager(null);
MyDaoAuthenticationProvider authenticationProvider = new MyDaoAuthenticationProvider(Constants.LOGIN_USERNAME, Constants.LOGIN_PASSWORD);
authenticationProvider.setPasswordEncoder(passwordEncoder());
authenticationProvider.setUserDetailsService(inMemoryUserDetailsManager());
authenticationManagerBuilder.authenticationProvider(authenticationProvider);
http.authenticationManager(authenticationManagerBuilder.build());
return http.build();
}
小黑: "SecurityFilterChain
表示一个Filter
集合, 更直接点就是子类的AuthenticationManager
"
小黑: "所以这种玩法是给子类AuthenticationManager
添加Provider
, 但是它需要手动将parent
置为 null
, 否则父类的DaoAuthenticationProvider
还是会执行, 最后报错信息就不对了, 本来应该是验证码错误, 将会变成用户名和密码错误"
小黑: "还有就是, 很多人很喜欢在旧版本像下面这么玩"
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
MyDaoAuthenticationProvider authenticationProvider = new MyDaoAuthenticationProvider(Constants.LOGIN_USERNAME, Constants.LOGIN_PASSWORD);
authenticationProvider.setPasswordEncoder(passwordEncoder());
authenticationProvider.setUserDetailsService(inMemoryUserDetailsManager());
return new ProviderManager(authenticationProvider);
}
小黑: "在新版本也类似的这么搞, 但这样是有区别的, 下面这种方式只会加入到spring Bean上下文, 但是不会加入到Spring Security中执行, 他是无效的"
@Bean
public ProviderManager providerManager() throws Exception {
MyDaoAuthenticationProvider authenticationProvider = authenticationProvider();
return new ProviderManager(authenticationProvider);
}
小黑: "在新版本中, 使用上面那段代码是一点用都没有"
public MyDaoAuthenticationProvider authenticationProvider() throws Exception {
MyDaoAuthenticationProvider authenticationProvider = new MyDaoAuthenticationProvider(Constants.LOGIN_USERNAME, Constants.LOGIN_PASSWORD);
authenticationProvider.setPasswordEncoder(passwordEncoder());
authenticationProvider.setUserDetailsService(inMemoryUserDetailsManager());
return authenticationProvider;
}
// 往子类AuthenticationManager里面添加的 authenticationProvider
httpSecurity.authenticationProvider(authenticationProvider());
小黑: "上面这样做也是不行, 他还是会存在两个, 一个是MyDaoAuthenticationProvider
(子类), 另一个是DaoAuthenticationProvider
(父类)"
小白: "那最好的办法是什么?"
小黑: "直接将MyDaoAuthenticationProvider
添加到Spring Bean上下文"
@Bean
public MyDaoAuthenticationProvider authenticationProvider() throws Exception {
MyDaoAuthenticationProvider authenticationProvider = new MyDaoAuthenticationProvider(Constants.LOGIN_USERNAME, Constants.LOGIN_PASSWORD);
authenticationProvider.setPasswordEncoder(passwordEncoder());
authenticationProvider.setUserDetailsService(inMemoryUserDetailsManager());
return authenticationProvider;
}
小白: "那还有别的思路么?"
小黑: "还有么? 不清楚了, 万能网友应该知道"
小白: "就这样设置就行了? 其他还需不需要配置?"
小黑: "其他和过滤器方式一致"
@Bean
public MyDaoAuthenticationProvider authenticationProvider() throws Exception {
// 最好的办法就是直接MyDaoAuthenticationProvider加入到Spring Bean里面就行了, 其他都不要
MyDaoAuthenticationProvider authenticationProvider = new MyDaoAuthenticationProvider(Constants.LOGIN_USERNAME, Constants.LOGIN_PASSWORD);
authenticationProvider.setPasswordEncoder(passwordEncoder());
authenticationProvider.setUserDetailsService(inMemoryUserDetailsManager());
return authenticationProvider;
}
和
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// 代码省略
// 代码省略
// 代码省略
// 代码省略
// 往子类AuthenticationManager里面添加的 authenticationProvider, 但不能阻止 AuthenticationManger 父类加载 DaoAuthenticationProvider
AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
// 但是这种方式可以将 parent Manager 设置为 null, 所以是可以的
authenticationManagerBuilder.parentAuthenticationManager(null);
MyDaoAuthenticationProvider authenticationProvider = new MyDaoAuthenticationProvider(Constants.LOGIN_USERNAME, Constants.LOGIN_PASSWORD);
authenticationProvider.setPasswordEncoder(passwordEncoder());
authenticationProvider.setUserDetailsService(inMemoryUserDetailsManager());
authenticationManagerBuilder.authenticationProvider(authenticationProvider);
http.authenticationManager(authenticationManagerBuilder.build());
return http.build();
}
都是可以的, 一个往父类的AuthenticationManager
添加MyDaoAuthenticationProvider
, 另一个往子类添加, 设置父类为null
小白: "前后端分离和传统web项目的区别是什么?"
小黑: "请求request
和响应response
都使用JSON
传递数据"
小白: "那我们分析源码时只要关注 request
和 response
咯, 只要发现存在request的读, 和 response的写通通都要重写一边"
小黑: "是的, 其实很简单, 无非是图片验证码改用json
读, 认证时的读取username
和password
也使用json
读, 其次是出现异常需要响应response
, 也改成json
写, 认证成功和失败需要响应到前端也改成json
写"
小白: "哦, 那只要分析过源码, 就能够完成前后端分离功能了"
小黑: "所以还讲源码么? "
小白: "不用, 非常简单"
public class VerifyCodeFilter extends UsernamePasswordAuthenticationFilter {
@Resource
private ObjectMapper objectMapper;
@SneakyThrows
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (!"POST".equals(request.getMethod())) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
String contentType = request.getContentType();
HttpSession session = request.getSession();
if (MediaType.APPLICATION_JSON_VALUE.equals(contentType) || MediaType.APPLICATION_JSON_UTF8_VALUE.equals(contentType)) {
Map map = objectMapper.readValue(request.getInputStream(), Map.class);
imageJSONVerifyCode(session, map);
String username = (String) map.get(this.getUsernameParameter());
username = (username != null) ? username.trim() : "";
String password = (String) map.get(this.getPasswordParameter());
password = (password != null) ? password : "";
UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username,
password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
imageVerifyCode(request, session);
return super.attemptAuthentication(request, response);
}
private void imageJSONVerifyCode(HttpSession session, Map map) throws ValidateCodeException {
String verifyCode = (String) map.get(Constants.VERIFY_CODE);
String code = (String) session.getAttribute(Constants.VERIFY_CODE);
if (StrUtil.isBlank(verifyCode) || StrUtil.isBlank(code) || !StrUtil.equalsIgnoreCase(verifyCode, code)) {
throw new ValidateCodeException("验证码错误, 请重新获取验证码");
}
}
private void imageVerifyCode(HttpServletRequest request, HttpSession session) throws ValidateCodeException {
String verifyCode = request.getParameter(Constants.VERIFY_CODE);
String code = (String) session.getAttribute(Constants.VERIFY_CODE);
if (StrUtil.isBlank(verifyCode) || StrUtil.isBlank(code) || !StrUtil.equalsIgnoreCase(verifyCode, code)) {
throw new ValidateCodeException("验证码错误, 请重新获取验证码");
}
}
}
小白: "为什么你要写imageJSONVerifyCode
, imageVerifyCode
两个函数? 写一个不就行了?"
小黑: "额, 是的, 把参数改成两个String verifyCode, String code
也行"
@Configuration
public class SecurityConfig {
@Resource
private AuthenticationConfiguration authenticationConfiguration;
@Bean
PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
@Bean
public ObjectMapper objectMapper() throws Exception {
return new ObjectMapper();
}
@Bean
public VerifyCodeFilter verifyCodeFilter() throws Exception {
VerifyCodeFilter verifyCodeFilter = new VerifyCodeFilter();
verifyCodeFilter.setAuthenticationManager(authenticationConfiguration.getAuthenticationManager());
verifyCodeFilter.setAuthenticationFailureHandler((request, response, exception) -> {
HashMap<String, Object> map = new HashMap<>();
map.put("status", 401);
map.put("msg", exception.getMessage());
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.getWriter().write(JSONUtil.toJsonStr(map));
});
verifyCodeFilter.setAuthenticationSuccesshandler((request, response, authentication) -> {
HashMap<String, Object> map = new HashMap<>();
map.put("status", 200);
map.put("msg", "登录成功");
map.put("user", authentication);
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.getWriter().write(JSONUtil.toJsonStr(map));
});
return verifyCodeFilter;
}
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeHttpRequests()
.antMatchers(Constants.MATCHERS_LIST)
.permitAll()
.anyRequest()
.authenticated()
;
httpSecurity.formLogin()
.loginPage(Constants.LOGIN_PAGE)
.loginProcessingUrl(Constants.LOGIN_PROCESSING_URL)
.defaultSuccessUrl(Constants.SUCCESS_URL, true)
.permitAll();
httpSecurity.logout()
.clearAuthentication(true)
.invalidateHttpSession(true)
.logoutSuccessHandler((request, response, authentication) -> {
HashMap<String, Object> map = new HashMap<>();
map.put("status", 200);
map.put("msg", "注销成功");
map.put("user", authentication);
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.getWriter().write(JSONUtil.toJsonStr(map));
});
httpSecurity.csrf()
.disable();
httpSecurity.addFilterAt(verifyCodeFilter(), UsernamePasswordAuthenticationFilter.class);
httpSecurity.exceptionHandling()
.accessDeniedHandler((request, response, accessDeniedException) -> {
HashMap<String, Object> map = new HashMap<>();
map.put("status", 401);
map.put("msg", "您没有权限, 拒绝访问: " + accessDeniedException.getMessage());
// map.put("msg", "您没有权限, 拒绝访问");
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.getWriter().write(JSONUtil.toJsonStr(map));
})
.authenticationEntryPoint((request, response, authException) -> {
HashMap<String, Object> map = new HashMap<>();
map.put("status", HttpStatus.UNAUTHORIZED.value());
map.put("msg", "认证失败, 请重新认证: " + authException.getMessage());
// map.put("msg", "认证失败, 请重新认证");
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.getWriter().write(JSONUtil.toJsonStr(map));
});
return httpSecurity.build();
}
}
注意这两行代码, 教你怎么在不使用WebSecurityConfigurerAdapter
的情况下拿到AuthenticationManager
@RestController
@Slf4j
public class VerifyCodeController {
@GetMapping("/verify-code")
public void getVerifyCode(HttpServletResponse response, HttpSession session) throws Exception {
GifCaptcha captcha = CaptchaUtil.createGifCaptcha(Constants.IMAGE_WIDTH, Constants.IMAGE_HEIGHT);
RandomGenerator randomGenerator = new RandomGenerator(Constants.BASE_STR, Constants.RANDOM_LENGTH);
captcha.setGenerator(randomGenerator);
captcha.createCode();
String code = captcha.getCode();
session.setAttribute(Constants.VERIFY_CODE, code);
ServletOutputStream outputStream = response.getOutputStream();
captcha.write(outputStream);
outputStream.flush();
outputStream.close();
}
}
@Controller
@Slf4j
public class IndexController {
@GetMapping("login")
public String login() {
return "login";
}
@GetMapping("")
@ResponseBody
public Principal myIndex(Principal principal) {
return principal;
}
}
public class MyDaoAuthenticationProvider extends DaoAuthenticationProvider {
@Resource
private ObjectMapper objectMapper;
private final String loginUsername;
private final String loginPassword;
public MyDaoAuthenticationProvider(String loginUsername, String loginPassword) {
this.loginUsername = loginUsername;
this.loginPassword = loginPassword;
}
@SneakyThrows
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
assert requestAttributes != null;
HttpServletRequest request = requestAttributes.getRequest();
String contentType = request.getContentType();
String verifyCode = (String) request.getSession().getAttribute(Constants.VERIFY_CODE);
if (MediaType.APPLICATION_JSON_VALUE.equals(contentType) || MediaType.APPLICATION_JSON_UTF8_VALUE.equals(contentType)) {
Map map = this.objectMapper.readValue(request.getInputStream(), Map.class);
String code = (String) map.get(Constants.VERIFY_CODE);
imageVerifyCode(verifyCode, code);
String username = (String) map.get(loginUsername);
String password = (String) map.get(loginPassword);
UsernamePasswordAuthenticationToken authenticationToken = UsernamePasswordAuthenticationToken
.unauthenticated(username, password);
return super.authenticate(authenticationToken);
}
String code = request.getParameter(Constants.VERIFY_CODE);
imageVerifyCode(verifyCode, code);
return super.authenticate(authentication);
}
private void imageVerifyCode(String verifyCode, String code) throws ValidateCodeException {
if (StrUtil.isBlank(verifyCode) || StrUtil.isBlank(code) || !StrUtil.equalsIgnoreCase(verifyCode, code)) {
throw new ValidateCodeException("验证码错误, 请重新获取验证码");
}
}
}
@Slf4j
@Configuration
public class SecurityConfig {
private static final String NOOP_PASSWORD_PREFIX = "{noop}";
private static final Pattern PASSWORD_ALGORITHM_PATTERN = Pattern.compile("^\\{.+}.*$");
@Resource
private SecurityProperties properties;
@Bean
PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper();
}
@Bean
@Lazy
public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
SecurityProperties.User user = properties.getUser();
List<String> roles = user.getRoles();
return new InMemoryUserDetailsManager(
User.withUsername(user.getName()).password(getOrDeducePassword(user, passwordEncoder()))
.roles(StringUtils.toStringArray(roles)).build());
}
private String getOrDeducePassword(SecurityProperties.User user, PasswordEncoder encoder) {
String password = user.getPassword();
if (user.isPasswordGenerated()) {
log.warn(String.format(
"%n%nUsing generated security password: %s%n%nThis generated password is for development use only. "
+ "Your security configuration must be updated before running your application in "
+ "production.%n",
user.getPassword()));
}
if (encoder != null || PASSWORD_ALGORITHM_PATTERN.matcher(password).matches()) {
return password;
}
return NOOP_PASSWORD_PREFIX + password;
}
@Bean
public MyDaoAuthenticationProvider authenticationProvider() throws Exception {
MyDaoAuthenticationProvider authenticationProvider = new MyDaoAuthenticationProvider(Constants.LOGIN_USERNAME, Constants.LOGIN_PASSWORD);
authenticationProvider.setPasswordEncoder(passwordEncoder());
authenticationProvider.setUserDetailsService(inMemoryUserDetailsManager());
return authenticationProvider;
}
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests()
.antMatchers(Constants.MATCHERS_LIST)
.permitAll()
.anyRequest()
.authenticated()
;
http.formLogin()
.loginPage(Constants.LOGIN_PAGE)
.loginProcessingUrl(Constants.LOGIN_PROCESSING_URL)
.successHandler(new MyAuthenticationSuccessHandler())
.failureHandler(new MyAuthenticationFailureHandler())
.permitAll();
http.logout()
.clearAuthentication(true)
.invalidateHttpSession(true)
.logoutSuccessHandler(new MyLogoutSuccessHandler());
http.csrf()
.disable();
http.exceptionHandling(exceptionHandlinGConfigurer -> {
exceptionHandlingConfigurer.authenticationEntryPoint(new MyAuthenticationEntryPoint());
exceptionHandlingConfigurer.accessDeniedHandler(new MyAccessDeniedHandler());
})
;
return http.build();
}
private static class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
HashMap<String, Object> map = new HashMap<>();
map.put("status", 200);
map.put("msg", "认证成功");
map.put("user_info", authentication.getPrincipal());
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.getWriter().write(JSONUtil.toJsonStr(map));
}
}
private static class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
log.error("认证失败", exception);
exception.printStackTrace();
HashMap<String, Object> map = new HashMap<>();
map.put("status", 401);
map.put("msg", "认证失败");
map.put("exception", exception.getMessage());
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.getWriter().write(JSONUtil.toJsonStr(map));
}
}
private static class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
log.error("认证失效", authException);
HashMap<String, Object> map = new HashMap<>();
map.put("status", HttpStatus.UNAUTHORIZED.value());
map.put("msg", "认证失败, 请重新认证: " + authException.getMessage());
// map.put("msg", "认证失败, 请重新认证");
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.getWriter().write(JSONUtil.toJsonStr(map));
}
}
private static class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
log.error("没有权限", accessDeniedException);
HashMap<String, Object> map = new HashMap<>();
map.put("status", 401);
map.put("msg", "您没有权限, 拒绝访问: " + accessDeniedException.getMessage());
// map.put("msg", "您没有权限, 拒绝访问");
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.getWriter().write(JSONUtil.toJsonStr(map));
}
}
private static class MyLogoutSuccessHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
HashMap<String, Object> map = new HashMap<>();
map.put("status", 200);
map.put("msg", "注销成功");
map.put("user", authentication);
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.getWriter().write(JSONUtil.toJsonStr(map));
}
}
}
以上就是Spring Security实现添加图片验证功能的详细内容,更多关于Spring Security添加图片验证的资料请关注编程网其它相关文章!
--结束END--
本文标题: SpringSecurity实现添加图片验证功能
本文链接: https://lsjlt.com/news/176716.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-03-01
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0