用SpringSecurity从零搭建pc项目-01
注:之前写过一些列的SpringSecurity的文章,重新写一遍是为了把某些不必要的步骤省去,留下精简的,因为工作中有一些不需要。
在java的权限框架里,shiro和SpringSecurity是用的最多的。随着springboot的流行,SpringSecurity也越来越火了,因为springboot默认支持SpringSecurity。所以很有必要把SpringSecurity也搞明白。shiro更加轻量级,SpringSecurity的功能更加丰富。
软件环境:
开发工具:Idea
JDK:1.8
maven:3.3.9
* SpringBoot版本:1.5.18 (说明:springboot版本没有用最新版的2.0x,因为2.0x和1.5 差别比较大吧,2.x好似是基于spring5的,SpringSecurity的更新速度好似跟不上springboot,所以这里如果用springboot 2.x会有问题,保险起见这里就不求新了)
SpringSecurity核心功能:认证、授权、攻击防护(防止伪造身份)
话不多说,下边开始打代码。
一、项目搭建
1.1 热身 ,SpringSecurity默认的Httpbasic鉴权
1.1.1,新建项目

填好项目信息,next

选启动器:SpringSecurity、Web

设置项目目录。finish

建好后的项目结构:security包放有关SpringSecurity的代码

maven依赖:
<dependencies>
<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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
引入了SpringSecurity的starter后,会自动引入SpringSecurity相关的相关依赖:

1.1.2 访问我们的服务
新建一个Controller:
@RestController
public class UserController { @RequestMapping("/hello")
public String hello(){
return "Hello ! ";
}
}
启动项目,访问localhost:8080/hello,默认就会出来这个登录框,只要引入了SpringSecurity,springboot就默认会启用http basic认证,所有的服务都会被保护起来, ,。

其中的默认用户名是user,默认的密码在启动项目的时候会在控制台打印。

输入用户名密码,就能访问:


如果输入的用户名或密码错误,Springboot会引导你到一个空白页,这个也是可以配置的,后边再说怎么配置:

你还可以关闭这个默认的鉴权,只需在application.properties 里配置: security.basic.enabled = false ,这个值默认是true。
二、表单登录
如果想去掉那个比较丑的basic登录框,只需要一个配置类即可。新建配置类 BrowserSecurityConfig,继承 WebSecurityConfigurerAdapter
@EnableWebSecurity
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter { }
(为什么这么写?因为SpringSecurity官方文档这么说的https://docs.spring.io/spring-security/site/docs/4.2.10.RELEASE/reference/htmlsingle/#samples):
5.1 Hello Web Security Java配置
第一步是创建Spring Security Java配置。配置创建一个Servlet过滤器,称为springSecurityFilterChain负责应用程序内所有安全性(保护应用程序URL,验证提交的用户名和密码,重定向到登录表单等)。您可以在下面找到Spring Security Java配置的最基本示例:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.*;
import org.springframework.security.config.annotation.authentication.builders.*;
import org.springframework.security.config.annotation.web.configuration.*; @EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Bean
public UserDetailsService userDetailsService() throws Exception {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("user").password("password").roles("USER").build());
return manager;
}
}
然后启动application,访问http://localhost:8080/hello,可以看到已经出来了一个登录页面,输入用户名user,以及控制台打印的密码:
登录后 访问的是登录之前的要访问的hello服务:
官网说明:
到目前为止,我们的WebSecurityConfig仅包含有关如何验证用户身份的信息。Spring Security如何知道我们要求所有用户进行身份验证?Spring Security如何知道我们想要支持基于表单的身份验证?原因是WebSecurityConfigurerAdapter在configure(HttpSecurity http)方法中提供了一个默认配置,如下所示:
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic();
}
三、自定义用户认证逻辑
3.1 ,处理用户信息获取 、用户校验 、密码的加密解密
新建一个类,MyUserDetailService (这个类必须是Spring里的一个Bean,所以加上@Component注解)实现 UserDetailsService 接口,UserDetailsService 接口只有一个方法:通过用户名查询用户信息,返回UserDetail
UserDetailsService.java
public interface UserDetailsService {
UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}
UserDetails.java : 提供了几个方法,账户是否启用、账户是否过期、密码是否过期、账户是否锁定、权限集合信息
public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}
配置一个密码的加密解密器类:PasswordEncoder,我们用其一个实现类 BCryptPasswordEncoder,只有两个方法,一个是加密密码,一个是匹配方法。如果已有系统已经有了自己的加密算法,这里可以换成自己的加解密逻辑。
@Bean
public PasswordEncoder passwordencoder(){
//BCryptPasswordEncoder implements PasswordEncoder
return new BCryptPasswordEncoder();
}
这个接口的实现类会给加密的密码随机加盐,所以一样的密码每次加密出来是不一样的,更安全。如123456加密2次:
加密后密码: $2a$10$BChH.C4.X8MYuI1mHFoOkefWhOsad7SvhZedHFt1OG4vjSu.z9weC
加密后密码: $2a$10$YUbz.miE5C0aAcuU1FnHSu/U.Qm/BujTNw6X7S5i4/6AhjyDc6suK
此时我们的逻辑是,只要密码输入123456,就能登录成功。启动项目试验:访问/hello ,会自动跳转/login ,随便输入用户名aaaaaa,输入密码123456 ,成功访问Hello!
| 
3.2 自定义登录页面
用SpringSecurity提供的默认的登录页肯定是不行的,所以需要自定义登录页(当然这里还可以配置成一个Controller方法,然后跳转到登录页。或者从配置文件里读取),在BrowserSecurityConfig类里配置:
@Override
protected void configure(HttpSecurity http) throws Exception {
//http.httpBasic() //这个就是默认的弹框认证
http.formLogin() //表单认证
.loginPage("/login.html")
.loginProcessingUrl("/authentication/form")
.and()
.authorizeRequests() //下边的都是授权的配置
.antMatchers("/login.html").permitAll() //放过登录页不过滤
.anyRequest() //任何请求
.authenticated(); //都需要身份认证
}
.loginPage("/login.html") 配置登录页面
.loginProcessingUrl("/authentication/form") 配置处理登录表单的action,这个值默认在UsernamePasswordAuthenticationFilter 类里,

注意一定要放过登录页不过滤,否则一直不能跳转到login.html
此时访问 /hello ,跳转到自定义的登录页:

随便输入用户名,密码输入123456 ,登录,出现

SpringSecurity默认提供了CSRF(跨站请求伪造)防护,是用CSRF token来完成防护的。暂时关闭CSRF防护,在BrowserSecurityConfig里设置:
.csrf().disable();
再次登录,可以成功访问到 /hello服务。
至此自定义登录页面完成吗,下一步自定义登录成功处理。
也可以把登录页做成在配置文件application.properties里配置,然后在代码里读取配置,这样更灵活、更通用。
这里有springboot读取配置文件的用法:https://www.cnblogs.com/lihaoyang/p/10223339.html
3.2 自定义登录成功/失败处理
现在的流程是,访问一个需要登录的服务,如果没有登录,跳转登录页,等你登录后,立马就访问登录之前的服务。如果你想在登录成功后做一些处理,比如签到,送积分等等。那就需要自定义登录成功的处理。如果没有这种需求,这一步骤可以略过。
springsecurity提供了一个接口,AuthenticationSuccessHandler,用来处理登录成功后的逻辑:
/**
* Strategy used to handle a successful user authentication.
* <p>
* Implementations can do whatever they want but typical behaviour would be to control the
* navigation to the subsequent destination (using a redirect or a forward). For example,
* after a user has logged in by submitting a login form, the application needs to decide
* where they should be redirected to afterwards (see
* {@link AbstractAuthenticationProcessingFilter} and subclasses). Other logic may also be
* included if required.
*
* @author Luke Taylor
* @since 3.0
*/
public interface AuthenticationSuccessHandler { /**
* Called when a user has been successfully authenticated.
*
* @param request the request which caused the successful authentication
* @param response the response
* @param authentication the <tt>Authentication</tt> object which was created during
* the authentication process.
*/
void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException; }
1,定义一个自己的成功处理器,实现这个Handler:
package com.lhy.browser.security.authentication; import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; /**
* 认证成功处理器
*/
@Component("myAuthenticationSuccessHandler")
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler { private Logger logger = LoggerFactory.getLogger(getClass()); //springmvc启动会自动注册一个ObjectMapper
@Autowired
private ObjectMapper objectMapper; @Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { logger.info("登录成功");
//把authentication返回给响应
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(authentication)); }
}
2、添加到配置类,让spring security执行自定义的处理器
在 BrowserSecurityConfig 配置类里注入 AuthenticationSuccessHandler
@EnableWebSecurity
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter { //自定义的认证成功的处理器
@Autowired
private AuthenticationSuccessHandler myAuthenticationSuccessHandler;
//自定义的认证失败的处理器
@Autowired
private AuthenticationFailureHandler myAuthenticationFailureHandler; @Autowired
private SecurityProperties securityProperties; @Override
protected void configure(HttpSecurity http) throws Exception {
//http.httpBasic() //这个就是默认的弹框认证
http.formLogin() //表单认证
.loginPage(securityProperties.getBrowser().getLoginPage())//登录页
.loginProcessingUrl("/authentication/form") //登录提交action
.successHandler(myAuthenticationSuccessHandler) //自定义的认证成功处理器
.failureHandler(myAuthenticationFailureHandler)//自定义的认证失败的处理器
.and()
.authorizeRequests() //下边的都是授权的配置
.antMatchers(securityProperties.getBrowser().getLoginPage()).permitAll() //放过登录页不过滤
.anyRequest() //任何请求
.authenticated() //都需要身份认证
.and()
.csrf().disable();
} }
登录失败处理器和登录成功类似,自定义失败处理类,实现 AuthenticationFailureHandler 接口即可:
/**
* 认证失败处理器
*/
@Component("/myAuthenticationFailureHandler")
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler { private Logger logger = LoggerFactory.getLogger(getClass()); //springmvc启动会自动注册一个ObjectMapper
@Autowired
private ObjectMapper objectMapper; @Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
logger.info("登录失败"); //把authentication返回给响应
//状态码500,服务器内部错误
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(exception.getMessage()));
}
}
这样就可以在登录成功和失败后进入自己的处理逻辑了。
用SpringSecurity从零搭建pc项目-01的更多相关文章
- 用SpringSecurity从零搭建pc项目-02
参照这一篇文章吧,比如你不需要做的那么通用,取其中一部分代码即可. https://www.cnblogs.com/lihaoyang/p/8491792.html
- 腾讯云centos7 从零搭建laravel项目
目标,访问网站出现: -----------------------分割线---------------------------------------- 一.Laravel Homestead 环境 ...
- SpringBoot整合SpringSecurity简单实现登入登出从零搭建
技术栈 : SpringBoot + SpringSecurity + jpa + freemark ,完整项目地址 : https://github.com/EalenXie/spring-secu ...
- 零配置简单搭建SpringMVC 项目
SpringMVC是比较常用的JavaWeb框架,非常轻便强悍,能简化Web开发,大大提高开发效率,在各种Web程序中广泛应用.本文采用Java Config的方式搭建SpringMVC项目,并对Sp ...
- 从零搭建一个SpringCloud项目之Feign搭建
从零搭建一个SpringCloud项目之Feign搭建 工程简述 目的:实现trade服务通过feign调用user服务的功能.因为trade服务会用到user里的一些类和接口,所以抽出了其他服务需要 ...
- 从零搭建一个IdentityServer——项目搭建
本篇文章是基于ASP.NET CORE 5.0以及IdentityServer4的IdentityServer搭建,为什么要从零搭建呢?IdentityServer4本身就有很多模板可以直接生成一个可 ...
- 从零搭建基于webpack的Electron-Vue3项目(1)——基于webpack的Vue3项目搭建
从零搭建基于webpack的Electron-Vue3项目(1)--基于webpack的Vue3项目搭建 前言 本篇文章内容,主要是基于webpack的Vue3项目开发环境进行搭建,暂时还不涉及到El ...
- 从零搭建react hooks项目(github有源代码)
前言 首先这是一个react17的项目,包含项目中常用的路由.状态管理.less及全局变量配置.UI等等一系列的功能,开箱即用,是为了以后启动项目方便,特地做的基础框架,在这里分享出来. 这里写一下背 ...
- 01.基于IDEA+Spring+Maven搭建测试项目--综述
目前公司的测试工作中常见两种接口:HTTP和Dubbo,这两种接口类型均可以使用相关测试工具进行测试,但都会有一定的局限性和不便之处,具体如下: 1.HTTP接口,当需要对于参数进行加密解密时,就得对 ...
随机推荐
- Java中方法重写和方法重载
首先方法重写和方法重载是建立在Java的面向对象的继承和多态的特性基础上而出现的.至于面向对象的继承和多态的特性我就不在这里多说了.继承是指在一个父类的基础再创建一个子类,这样子类就拥有了父类的非私 ...
- Codeforces820A Mister B and Book Reading 2017-06-28 09:38 67人阅读 评论(0) 收藏
A. Mister B and Book Reading time limit per test 2 seconds memory limit per test 256 megabytes input ...
- Surface 2装机必备软件指南
新买的Surface到货了还不知道有什么用,每天就用来划划点点?有点太浪费了吧!跟哥走,哥给你推荐几款Surface 2装机必备的软件~应用商店,走起~ 初次使用看过来:Win8宝典 如果你是一个像我 ...
- STL-容器库000
容器库已经作为class templates 实现. 容器库中是编程中常用的结构: (1)动态数组结构vector: (2)队列queue: (3)栈stack: (4)heaps 堆priority ...
- Scala_模式匹配
模式匹配 简单匹配 Scala的模式匹配最常用于match语句中.下面是一个简单的整型值的匹配实例 object TestMatch { def main(args: Array[String]): ...
- 调用DLL窗体-Delphi实例
(一)通过向导DLL Wizard新建一个动态链接库,取名为:DLLPro.dpr.说明:当在DLL工程文件中使用了String类型时,要有 uses ShareMem ,不过建议使用PChar类型. ...
- applicationContext.xml 基本配置
<!-- 头文件,主要注意一下编码 --><?xml version="1.0" encoding="UTF-8"?><beans ...
- docker - 从安装到部署一个web应用(go、java)
一:安装docker 1.https://docs.docker.com/engine/installation/binaries/ 下载docker最新版二进制tar.gz linux下: wget ...
- GridControl简单属性操作
1.单行记录整行选中 GridView->OptionsBehavior->EditorShowMode 设置为:Click 2.如何让行只能选择而不能编辑(或编辑某一单元格) 只读 Gr ...
- WPF 分享一种背景动画效果
今天看微软的一个Samples,发现一个蛮好玩的背景样式,如下图所示: 风格比较卡哇伊. <Window x:Class="WPFSamplesTest.MainWindow" ...
