http basic 安全验证
在第一章构建项目中说到
当项目依赖中 含有 spring security 的jar 包时
它会有一个默认的安全配置http basic
所有一开始我们用下面的注解移除掉了它的默认安全配置
spring security 默认的安全验证我们一般是不用的
实现用户名+密码认证
开始开发基于表单的安全验证
创建 BrowserSecurityConfig 类 配置安全验证
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() //指定身份认证的方式为表单登录
.and()
.authorizeRequests() //对请求授权
.anyRequest() //任何请求
.authenticated(); //安全认证
//任何请求都必须经过表单验证才能进行访问
}
}
运行并测试
直接运行我们这个项目 demoApplication ,发现报错
No qualifying bean of type 'org.springframework.security.config.annotation.ObjectPostProcessor<?>' available
2019-04-06 19:31:05.208 INFO 18932 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
https://stackoverflow.com/questions/32081578/spring-security-nosuchbeandefinitionexception-no-qualifying-bean-of-type-org
原因是我们关闭了spring security的安全验证配置
把红框里的注解去掉
再次运行 成功
访问 http://localhost:8080/hello 后会跳到登录界面
用户名为 user
密码 在 控制台打印出了,这个密码每次启动都会变
这样就可以了
基本原理
主要是由一层层过滤器构成····
自定义用户认证逻辑
处理用户信息获取逻辑
用户信息的获取 在 spring security 中是被 封装在 userDetailService 接口中
自定义自己的userDetailService 实现类
@Component
public class MyUserDetailsService implements UserDetailsService {
// 这里注入dao 层 用于查询数据库
Logger logger = LoggerFactory.getLogger(getClass());
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
//根据用户名从数据库查找用户信息
logger.info("登录用户名"+ userName);
//我们要验证用户名 密码 并 查取权限
//这个user是spring中的类,它实现了UserDetails 接口
User admin = new User(userName, "123456",
AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));//第三个参数是做授权的
return admin;
}
}
启动应用 访问 http://localhost:8080/hello 输入用户密码后台报错
原因:版本升级 因为Spring security 5.0中新增了多种加密方式,也改变了密码的格式。
https://spring.io/blog/2017/11/01/spring-security-5-0-0-rc1-released
https://docs.spring.io/spring-security/site/docs/5.0.0.RELEASE/reference/htmlsingle/#ns-password-encoder
https://www.cnblogs.com/majianming/p/7923604.html
https://blog.youkuaiyun.com/Canon_in_D_Major/article/details/79675033
解决:待会解决 需要配置 PasswordEncoder
处理用户校验逻辑
用户是否冻结,密码是否过期等验证信息
处理密码加密解密逻辑
配置 PasswordEncoder
修改 MyUserDetailsService 的 loadUserByUsername 的方法
测试成功 ,也解决了之前的问题
注意 密码都是123456 ,但每次打印出来得密码都不一样 不像md5
因为他会随机生成一个盐,将随机生成的盐混在密码串里面,当他判断的时候 再用随机生成的盐来反推当时的密码串
一些问题restful返回及登录路径可配置
1、我们前面说过restful返回的应该是状态码和json信息,但现在认证成功后返回的是一个html页面
解决思路:如果是html请求就跳转到登录页面上,如果不是就返回json
2、代码重构,使其可以自定义配置登录页面。
处理不同类型的请求
@RestController
public class BrowserSecurityController {
private Logger logger = LoggerFactory.getLogger(getClass());
private RequestCache requestCache = new HttpSessionRequestCache();//缓存到session中的请求
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();//请求跳转工具
@Autowired
private SecurityProperties securityProperties;
/**
* 当需要身份认证时,跳转到这里
*
* @param request
* @param response
* @return
* @throws IOException
*/
@RequestMapping("/anthentication/require")
@ResponseStatus(code = HttpStatus.UNAUTHORIZED)//401未授权状态码
public SimpleResponse requireAuthentication(HttpServletRequest request, HttpServletResponse response)
throws IOException {
//拿到引发跳转的这个请求
SavedRequest savedRequest = requestCache.getRequest(request, response);
if (savedRequest != null) {
String targetUrl = savedRequest.getRedirectUrl();
logger.info("引发跳转的请求是:" + targetUrl);
if (StringUtils.endsWithIgnoreCase(targetUrl, ".html")) {
redirectStrategy.sendRedirect(request, response, securityProperties.getBrowser().getLoginPage());// securityProperties.getBrowser().getLoginPage()配置登录页面