SpringBoot2.0整合SpringSecurity实现自定义表单登录

我们知道企业级权限框架一般有Shiro,Shiro虽然强大,但是却不属于Spring成员之一,接下来我们说说SpringSecurity这款强大的安全框架。费话不多说,直接上干货。

pom文件引入以下依赖:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>

首先创建WebConfig继承WebSecurityConfigurerAdapter,实现代码如下:


import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.Session;
import org.springframework.session.data.redis.RedisOperationsSessionRepository;

/**
 * author:yuxuan
 * date:2018/12/16/016 12:00
 * description 
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyAuthenticationSuccessHandler myAuthenticationSuccess;
    @Autowired
    private MyAuthenticationProvider myAuthenticationProvider;
    @Autowired
    private MyAuthenticationFailHandler myAuthenticationFailHandler;
    @Autowired
    private MyUserDetailService myUserDetailService;
    @Autowired
    private HikariDataSource dataSource;


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(myAuthenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.headers().frameOptions().sameOrigin();
        http.csrf()
                .disable()
                .authorizeRequests()
                .antMatchers("/static/**","/resources/**","/login/userauth").permitAll()
                .antMatchers("/health","/autoconfig","/configprops","/beans","/dump","/env","/env/**","/info","/mappings","/metrics","/metrics/**","/shutdown","/trace").hasRole("SYS")
                .anyRequest().authenticated()
                .and().formLogin().loginPage("/login")
                .successHandler(myAuthenticationSuccess)
                .failureHandler(myAuthenticationFailHandler)
                .permitAll()
                .and()
                .logout().deleteCookies("SESSION", "remember-me")
                .and().sessionManagement().maximumSessions(1).maxSessionsPreventsLogin(true).expiredUrl("/login").and()
                .and().rememberMe().alwaysRemember(true).tokenRepository(persistentTokenRepository())
                .tokenValiditySeconds(60 * 60 * 24 * 7)  //设置记住我的时间为7天
                .userDetailsService(myUserDetailService)//设置userDetailsService
                ;
        http.headers().cacheControl(); //禁用缓存
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
                .antMatchers( "/api/**", "/resources/**", "/static/**", "/public/**", "/webui/**", "/h2-console/**"
                        , "/configuration/**",  "/swagger-resources/**", "/api-docs", "/api-docs/**", "/v2/api-docs/**"
                        ,  "/**/*.css", "/**/*.js","/**/*.ftl", "/**/*.png ", "/**/*.jpg", "/**/*.gif ", "/**/*.svg", "/**/*.ico", "/**/*.ttf", "/**/*.woff");
    }



    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        return tokenRepository;
    }
}

以上为SpringSecurity的主要配置类,包括登录,退出,拦截那些url等。

MyAuthenticationProvinder类,主要实现认证


import lombok.extern.log4j.Log4j;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

import java.util.Collection;

@Log4j2
@Component
public class MyAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private MyUserDetailService myUserDetailService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        String userName = authentication.getName();// 这个获取表单输入中的用户名
        String password = (String) authentication.getCredentials();
        log.info("登陸用戶:"+userName);
        UserInfo userInfo = (UserInfo) myUserDetailService.loadUserByUsername(userName);
        
        String pwd = MD5Utils.encryptMD5Pwd(password,userInfo.getSalt());
        System.out.println(pwd);
        if(!pwd.equals(userInfo.getPassword())){
            throw new UsernameNotFoundException("用户名或者密码不正确");
        }

        Collection<? extends GrantedAuthority> authorities = userInfo.getAuthorities();

        return new UsernamePasswordAuthenticationToken(userInfo, pwd, authorities);

    }

    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }
}

创建类MyUserDetailService实现UserDetailService


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class MyUserDetailService implements UserDetailsService {

    @Autowired
    private UserRepo userRepo;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {

        //UserInfo userInfo = new UserInfo(1,"張三","abc","sdf",1);
        User user = userRepo.findFirstByAccount(s);
        if(user ==null){
            user = userRepo.findFirstByMobile(s);
            if(user == null){
                throw new UsernameNotFoundException("用户名或者密码不正确");
            }
        }
        //保存最后一次登录日志
                user.setLastLoginTime(new Date());
        userRepo.save(user);
        UserInfo userInfo = new UserInfo(
                user.getId(),
                user.getPassword(),
                user.getSalt(),
                user.getStatus(),
        return userInfo;
    }
}

创建类 MyAuthenticationSuccessHandler 继承 AuthenticationSuccessHandler 此类主要是SpringSecurity登录成功后的处理逻辑


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
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler{
    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        httpServletResponse.sendRedirect("/index");
    }
}

创建类 MyAuthenticationFailHandler继承 AuthenticationFailHandler 此类主要是SpringSecurity登录失败后的处理逻辑


import lombok.extern.log4j.Log4j2;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Log4j2
@Component
public class MyAuthenticationFailHandler implements AuthenticationFailureHandler {

    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        log.info(e.getMessage());
        httpServletRequest.setAttribute("msg","");
        if(e instanceof UsernameNotFoundException){
            httpServletRequest.setAttribute("msg","用戶名或者密碼錯誤");
        }
        httpServletRequest.getRequestDispatcher("/login").forward(httpServletRequest,httpServletResponse);

    }
}

以上为主要配置,启动项目,访问/login会要求输入用户名密码。

posted @ 2019-01-22 15:26  坐看云起时_雨宣  阅读(627)  评论(0编辑  收藏  举报