Spring Security实现登陆以及权限认证
1.Spring Security是怎么鉴权和实现权限认证的呢?
一般我们会创建一个Spring Security的配置来进行权限的认证设置、各种拦截策略以及各种自定义的配置。
1.1 创建Spring Security配置类
只要继承了WebSecurityConfigurerAdapter抽象类并且加上Spring的配置注解@Configuration以及将Bean放到容器中管理的 @EnableWebSecurity注解和@EnableGlobalMethodSecurity(prePostEnabled=true)就可以完成一个Spring Security的配置类的创建,实现全局生效自定义的安全配置。在创建完成后,可以重载里面很多设置配置的方法,如下图所示:
1.2 其中有很多public void configure这个的重载方法,用于配置不同的拦截策略。
用于根据系统自定义一些拦截策略,provider就实现了AuthenticationProvider接口的自定义配置处理类
1.2.1 下面这种AuthenticationManagerBuilder auth参数的是身份验证提供程序是需要自定义配置的。
@Override public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(provider);
}
provider是实现了AuthenticationProvider接口的自定义配置处理类,provider自定义类中实现方法public Authentication authenticate(Authentication authentication)中可以设置一些自定义的属性值,也可以从authentication参数中获取登录的用户名和密码。
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
CustomWebAuthenticationDetails details = (CustomWebAuthenticationDetails) authentication.getDetails();
String username = authentication.getName();
String password = (String) authentication.getCredentials();
String imgCode = details.getImgCode();
... ...
}
如果想要配置一些别的参数比如验证码可以通过继承WebAuthenticationDetails类设置自定义的一些属性,可以从请求参数中获取到这些参数,再在上面的安全拦截的配置类中强转为这个自定义的类从中就可以获取我们需要设置的自定义的安全配置了。
//比如可以配置验证码
public class CustomWebAuthenticationDetails extends WebAuthenticationDetails {
private final String imgCode;
public CustomWebAuthenticationDetails(HttpServletRequest request) {
super(request);
imgCode = request.getParameter("imgCode");
}
public String getImgCode() { return imgCode; }
}
还有一种配置是下面这样的,可以设置内存指定的登录的账号密码,指定角色,不加.passwordEncoder(new MyPasswordEncoder())或者注入该类的Bean就不是以明文的方式进行匹配,会报错,如果加上就需要配置自己myUserService跟数据库配置自定义查询,然后配置自定义的加密解密的配置类MyPasswordEncoder,实现不明文传输 。
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN");
auth.inMemoryAuthentication().withUser("demo").password("demo").roles("ADMIN");
auth.inMemoryAuthentication().withUser("testRole").password("testRole").roles("AD");
auth.userDetailsService(myUserService).passwordEncoder(new MyPasswordEncoder());
}
其中myUserService是配置自定义的数据库配置
@Component
public class MyUserService implements UserDetailsService{
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
return null;
}
}
其中new MyPasswordEncoder()可以配置加密
@Component
public class MyPasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(charSequence.toString());
}
//private final static String SALT = "这个是自定义的salt";
// @Override
// public String encode(CharSequence charSequence) { //
// return MD5Util.MD5Encode(charSequence.toString(),SALT); // } //
// @Override
// public boolean matches(CharSequence rawPassword, String encodedPassword) { //
// return MD5Util.isPasswordValid(encodedPassword,rawPassword.toString(),SALT); // }
}
1.2.2 参数是HttpSecurity http的是主要的接口请求拦截配置
这里就是主要的安全拦截配置了,可以在其中配置登录相关的处理,成功和失败的相关响应,配置登录和登出接口的定义(这里配置后可以不用在控制器中再配置相关接口,只需要在拦截器中配置好相关的安全参数的拦截策略就可以,在访问配置登录接口时,会自动进入到自定义的拦截器中进行参数判断)。还有很多其他配置,目前还在探索中。。。
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// 关闭csrf防护
.csrf().disable().headers().frameOptions().disable().and();
http
// 登录处理
.formLogin().authenticationDetailsSource(authenticationDetailsSource)
// 自定义登陆接受参数名
.usernameParameter("username").passwordParameter("password")
// 定义登录页面
.loginPage("/login")
// 登录处理接口
.loginProcessingUrl("/admin/login")
// 登录成功后处理
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.append("{\"code\": 0,\"msg\": \"ok\"}");
writer.flush();
writer.close();
}
})
// 登录失败后处理
.failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
String writerStr = "{\"code\": 1,\"msg\": \"error\"}";
if (exception instanceof MyException) {
MyException e = (MyException) exception;
RespModel resp = new RespModel(e.getCode(), e.getMsg());
writerStr = JSON.toJSONString(resp);
}
response.setContentType("application/json;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.append(writerStr);
writer.flush();
writer.close();
}
}).permitAll().and()
// 退出登录
.logout().logoutUrl("/logout").permitAll();
http.authorizeRequests().anyRequest().authenticated().and();
// Session的并发控制,这里设为最多一个,只允许一个用户登录,如果同一个账户两次登录,那么第一个账户将被踢下线
http.sessionManagement().maximumSessions(1).expiredUrl("/login");//自己实现的userDetail要重写EqualsAndHashCode 注解:@EqualsAndHashCode(callSuper = true)
// 当一个用户已经认证过了,在另外一个地方重新进行登录认证,spring security可以阻止其再次登录认证,从而保持原来的会话可用性
// 存在一个问题,当用户登陆后,没有退出直接关闭浏览器,则再次打开浏览器时,此时浏览器的session若被删除的话,用户只能等到服务器的session过期后,才能再次登录。
//http.sessionManagement().maximumSessions(1).maxSessionsPreventsLogin(true);
}
1.2.3 参数是WebSecurity web是配置静态资源
可以设置忽略拦截静态资源的路径等一些配置。
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/js/**", "/css/**", "/img/**", "/html/**", "/error");
}
以上就是目前探索的一些Spring Secrity的一些安全认证和鉴权策略的实现配置方法,继续探索ing...
- 点赞
- 收藏
- 关注作者
评论(0)