/**
* @Author fei
* @Date 2021/1/2 3:43 下午
*
* @Configuration用于定义配置类,定义的配置类可以替换xml文件,一般和@Bean注解联合使用。
* @Configuration注解主要标注在某个类上,相当于xml配置文件中的<beans>
* @Bean注解主要标注在某个方法上,相当于xml配置文件中的<bean>
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 必须要有这个实例 NoOpPasswordEncoder.getInstance() 这是一个过期的方法。
* @return
*/
@Bean
PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();//获取这个不加密的实例 为了下面的用户名对应的密码不加密 直接123就可以登录
}
/**
* 设置用户和密码 以及角色
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//在内存中配置密码
auth.inMemoryAuthentication()
.withUser("ppf").password("123").roles("admin")
.and()
.withUser("ask").password("123").roles("user");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() //开启授权方法
.antMatchers("/admin/**").hasRole("admin") //匹配器,在/admin/**这个地址要进行权限配置,赋予一个角色 admin
//.antMatchers("user/**").hasAnyRole("admin","user") //hasAnyRole 表示具备这两个角色其中一个就可以
.antMatchers("/user/**").access("hasAnyRole('user','admin')") //这个和上面的一个意思
.anyRequest().authenticated() //anyRequest 表示其他没有需要授权的地址,登录之后就能访问。 authenticated 已验证的 登录之后能访问
.and()
.formLogin() //上面配完之后呢,下面还需要配置表单登录
.loginProcessingUrl("/doLogin") //表示处理登录请求的url 这个配不配都可以,主要是方便用postman 来测试接口时用
.loginPage("/login") //这个表示需要登录,则跳转到/login这个url 一般前后端分离 不需要配置这个
.usernameParameter("uname") //这个表示 讲username这个属性名字改成uname,密码也是同理
.passwordParameter("passwd") //所以接口就应该这样写 http://localhost:8080/doLogin?uname=ppf&passwd=123 一般来说这个没有必要配置
//successHandler 表示前后端分离的项目,登录成功后,需要跳转的页面,这时候,后端只要返回json给前端(登录成功的一个处理器)
.successHandler(new AuthenticationSuccessHandler() {
@Override //参数 authentication 是保存了登录成功的用户信息
public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
resp.setContentType("application/json;chartset=utf-8"); //设置要返回的json格式
PrintWriter out = resp.getWriter();
Map<String, Object> map = new HashMap<>();
map.put("status",200);
map.put("msg",authentication.getPrincipal()); //authentication.getPrincipal() 就是登录成功的用户信息
out.write(new ObjectMapper().writeValueAsString(map)); //这是写出去的 转成json串
out.flush();
out.close();
}
})
//这个是登录失败的一个处理器,与上面类似。比如登录失败,服务端要跳到哪个页面去
.failureHandler(new AuthenticationFailureHandler() {
@Override //这边只有异常,异常可以锁定出错的问题
public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException e) throws IOException, ServletException {
resp.setContentType("application/json;chartset=utf-8"); //设置要返回的json格式
PrintWriter out = resp.getWriter();
Map<String, Object> map = new HashMap<>();
map.put("status",401);
if(e instanceof LockedException){ //nstanceof 运算符是用来在运行时指出对象是否是特定类的一个实例
map.put("msg","账户被锁定,登录失败!");
}else if (e instanceof BadCredentialsException){
map.put("msg","用户名或密码错误,登录失败!");
}else if (e instanceof DisabledException){
map.put("msg","账户被禁用,登录失败!");
}else if (e instanceof AccountExpiredException){
map.put("msg","账户过期,登录失败!");
}else if (e instanceof CredentialsExpiredException){
map.put("msg","密码过期,登录失败!");
}else {
map.put("msg","登录失败!");
}
out.write(new ObjectMapper().writeValueAsString(map)); //这是写出去的 转成json串
out.flush();
out.close();
}
})
.permitAll() //这个表示和登录相关的接口 直接就可以访问。 permit 英文是 许可的意思
.and()
//这边配置注销登录配置
.logout()
.logoutUrl("/logout") //这是注销登录的url
//这是注销登录成功的一个处理方法,返回前台json数据
.logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
resp.setContentType("application/json;chartset=utf-8"); //设置要返回的json格式
PrintWriter out = resp.getWriter();
Map<String, Object> map = new HashMap<>();
map.put("status",200);
map.put("msg","注销登录成功"); //authentication.getPrincipal() 就是登录成功的用户信息
out.write(new ObjectMapper().writeValueAsString(map)); //这是写出去的 转成json串
out.flush();
out.close();
}
})
.and()
.csrf().disable(); //这边表示 关闭 csrf攻击(跨站请求伪造) 为了防止测试时报错
}
}
|