安全管理:
认证:确认用户是否登录,对登录进行管控
授权:确定用户的权限,对用户权限进行管理
步骤:
1.添加依赖
启动项目,自定义进行安全管理(默认的安全管理模式)
2.自定义安全管理配置
创建配置类:webSecurityConfigureAdapter(去继承它)
重写这两个方法:
config(AuthenticationManagerBuilder auth):设置认证方式
config(HttpSecuritr http):设置访问控制
还有给这个类加上这个注解
@EnableWebSecurity:开启MVC Security安全支持
JDBC认证:
创建表格:
用户表:
username:值唯一
布尔类型的字段:用户是否有效
密码:必须进行加密操作
权限表:
数据要求:
ROLE_名字
用户权限关联关系表:
进行jdbc认证sql:
(1)查询username、password、validate(用户是否有效)
(2)查询username、authority(权限)
创建工具类(config层)
SecurityConfig类
package com.lxyk.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.security.servlet.WebSecurityEnablerConfiguration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.Collection;
/**
* 登录判断
*/
@EnableWebSecurity //开启MVC Security安全支持
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
DataSource dataSource;
@Value("${COOKIE.VALIDITY}")
private Integer validate;
//设置访问控制
@Override
protected void configure(HttpSecurity http) throws Exception {
//1.自定义用户访问控制
http.authorizeRequests()
.antMatchers("/", "/articleDetial/**", "/page/**", "/login")
.permitAll()
.antMatchers("/article_img/**", "/assets/**", "/back/**", "/user/**")
.permitAll()
.antMatchers("/admin/**")
.hasRole("admin")
.anyRequest()
.authenticated(); //hasRole:管理进入后台,第一个antMatchers代表前端放行,后面的代表要权限管理
//2.登录控制
http.formLogin()
.loginPage("/login") //登录页面的跳转路径(如果要跳转到自己的登录页面,就向后台发送这个请求)
.usernameParameter("username")
.passwordParameter("password")
//判断成功或失败
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
//1.获取到拦截页面
HttpSessionRequestCache requestCache = new HttpSessionRequestCache(); //Http 会话请求缓存
//2.跳转到当时访问过来的页面(如:在付款的时候选择登录)
String url = httpServletRequest.getParameter("url");
SavedRequest request = requestCache.getRequest(httpServletRequest, httpServletResponse);
//在从request中获取到页面的拦截地址
//判断
if (request != null) {
//跳转到拦截地址页面
httpServletResponse.sendRedirect(request.getRedirectUrl()); //重定向到 从请求域中获取到的获取重定向网址
} else if (url != null & url != "") {
//跳转到原始访问页面(如:在付款的时候选择登录)
httpServletResponse.sendRedirect(url);
} else {
//提转到主页
//既然要跳转到主页,那么:如果是管理员admin--》后台首页 /admin
//如果不是管理员 --》前台首页 /
//怎么获取权限?
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities(); //获取到权限
//当前用户可能有多个权限,所以是Collection
boolean isAdmin = authorities.contains(new SimpleGrantedAuthority("ROLE_admin"));//判断它里面有没有
if (isAdmin) {
//如果是管理员admin--》后台首页 /admin
httpServletResponse.sendRedirect("/admin");
} else {
//如果不是管理员 --》前台首页
httpServletResponse.sendRedirect("/");
}
}
}
})
//失败
.failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
//回到登录页面,重新登录
//获取原始访问路径
String url = httpServletRequest.getParameter("url");
httpServletResponse.sendRedirect("/login?error&url=" + url); //这里有个小细节error前端页面login中有如果登录错误会有提示信息,带着这个就会显示提示
}
});
//3.退出控制
http.logout()
.logoutUrl("/logout") //退出
.logoutSuccessUrl("/"); //退出后回到首页
//4 是否要开启记住我工能,设置cookie有效时间
http.rememberMe().alwaysRemember(true).tokenValiditySeconds(validate); //记住密码
}
//设置认证方式
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//JDBC方式认证
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
//JDBC身份认证SQL
//查询用户
String useSQL = "select username,password,valid from t_user where username=?";
//查询权限
String authoritySQL = "select a.username,b.authority " +
"from t_user a,t_authority b,t_user_authority c " +
"where a.id=c.user_id and b.id=c.authority_id and username=?";
auth.jdbcAuthentication()
.passwordEncoder(encoder)
.dataSource(dataSource)
.usersByUsernameQuery(useSQL)
.authoritiesByUsernameQuery(authoritySQL);
}
}
控制层添加方法
/**
* 登录跳转请求:跳转到登录页面
* @param request 请求域 获取原始访问路径和获取要额外去保存的路径
* @param map 把路径保存进去
* @return 把这个路径返回到登录页面当中
*/
@RequestMapping("/login")
public String longin(HttpServletRequest request, Map map) {
//保存原始访问路径 作用:往SecurityConfig工具类里送,保证它的功能
String referer = request.getHeader("Referer"); //获取原始访问路径,还需要去判断,不能直接用。因为如果登陆失败了存的就是失败的路径
String url = request.getParameter("url"); //获取原始访问路径(额外要去保存的)
System.out.println("referer=" + referer);
System.out.println("url=" + url);
//1.先判断保存的url
if (url != null && url != "") {
//使用url作为原始访问路径
map.put("url",url);
}else if (referer!=null&&referer.contains("login")){
//2.如果头信息中有login字段(是从登录---》登录)
map.put("url","");
}else {
//3.头信息作为原始访问路径
map.put("url",referer);
}
//跳转到登录页面
return "comm/login";
}