SpringBoot Security Session方式管理登陆信息

情到浓时终转凉″ 提交于 2021-01-06 16:53:36

一、说明

该实例采用 thymeleaf模板,基于Session会话管理的基础权限管理例子

二、项目开始

  • maven配置
<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.5</version>
			<scope>compile</scope>
		</dependency>
	</dependencies>







  • 基础handler配置
/**
 * 授权-没有权限处理器
 * @author huzhihui
 * @version $ v 0.1 2021/1/6 9:33 huzhihui Exp $$
 */
@Component
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
        ResponseUtils.sendJsonData(httpServletResponse, ResponseMessage.failure("权限不足"));
    }
}





/**
 * 未登陆的处理器
 * @author huzhihui
 * @version $ v 0.1 2021/1/6 9:32 huzhihui Exp $$
 */
@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        ResponseUtils.sendJsonData(httpServletResponse, ResponseMessage.failure("未登陆"));
    }
}





/**
 * 登陆认证失败处理器
 * @author huzhihui
 * @version $ v 0.1 2021/1/6 9:30 huzhihui Exp $$
 */
@Component
public class AuthenticationFailureHandlerImpl implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        ResponseUtils.sendJsonData(httpServletResponse, ResponseMessage.failure(e.getMessage()));
    }
}





/**
 * 登陆认证成功处理器
 * @author huzhihui
 * @version $ v 0.1 2021/1/6 9:29 huzhihui Exp $$
 */
@Component
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        ResponseUtils.sendJsonData(httpServletResponse, ResponseMessage.success(authentication));
    }
}





/**
 * 退出登录成功处理器
 * @author huzhihui
 * @version $ v 0.1 2021/1/6 9:34 huzhihui Exp $$
 */
@Component
public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler {
    @Override
    public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        ResponseUtils.sendJsonData(httpServletResponse, ResponseMessage.success("退出成功"));
    }
}





上面的处理器对应各个流程处理

三、采用默认form登陆并用默认登陆配置AuthenticationProvider如下

  • UserDetailsService的实现类
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		//此处应该是从数据库读取数据来验证
        if(username.equals("admin")){
            return new User(username,"$2a$10$99Mo0Mnpq6fyUTpsnLGVO.51WXKdY37YNMQFf88zx8.FOXYkcEzAS", AuthorityUtils.createAuthorityList("index","user"));
        }
        return new User(username,"$2a$10$99Mo0Mnpq6fyUTpsnLGVO.51WXKdY37YNMQFf88zx8.FOXYkcEzAS", AuthorityUtils.createAuthorityList("index"));
    }
}



@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;
    @Autowired
    private AuthenticationProviderImpl authenticationProvider;
    @Autowired
    private AccessDeniedHandlerImpl accessDeniedHandler;
    @Autowired
    private AuthenticationEntryPointImpl authenticationEntryPoint;
    @Autowired
    private AuthenticationFailureHandlerImpl authenticationFailureHandler;
    @Autowired
    private AuthenticationSuccessHandlerImpl authenticationSuccessHandler;
    @Autowired
    private LogoutSuccessHandlerImpl logoutSuccessHandler;

    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // 关闭csrf防护
                .csrf().disable()
                .headers().frameOptions().disable()
                .and();
        http
                .httpBasic()
                .authenticationEntryPoint(authenticationEntryPoint)
                .and()
                //登录处理
                .formLogin() //表单方式
                .loginPage("/login")
                .loginProcessingUrl("/login/submit")
                .defaultSuccessUrl("/index") //成功登陆后跳转页面
                .failureHandler(authenticationFailureHandler)
                .successHandler(authenticationSuccessHandler)
                .permitAll()
                .and();
        http.exceptionHandling()
                .accessDeniedHandler(accessDeniedHandler)
                .and();
        http.logout()
                .logoutSuccessHandler(logoutSuccessHandler)
                .and();
        http
                .authorizeRequests() // 授权配置
                //无需权限访问
                .antMatchers( "/css/**", "/error404").permitAll()
                //其他接口需要登录后才能访问
                .anyRequest().authenticated()
                .and();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 1、默认的登陆处理器,
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
        // 2、自己实现登陆逻辑处理
        //auth.authenticationProvider(authenticationProvider);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }




  • 登陆页面/login默认路由就存在不用配置,由于我重新定义了登陆验证路由,所以把form表单提交的url改为loginProcessingUrl("/login/submit")

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登陆</title>
    </head>
    <body>
    
    <form  class="form-signin" action="/login/submit" method="post">
        <h2 class="form-signin-heading">用户登录</h2>
        <table>
            <tr>
                <td>用户名:</td>
                <td><input type="text" name="username"  class="form-control"  placeholder="请输入用户名"/></td>
            </tr>
            <tr>
                <td>密码:</td>
                <td><input type="password" name="password"  class="form-control" placeholder="请输入密码" /></td>
            </tr>
            <tr>
    
                <td colspan="2">
                    <button type="submit"  class="btn btn-lg btn-primary btn-block" >登录</button>
                </td>
            </tr>
        </table>
    </form>
    </body>
    </html>
    
    
    
    
    
    

    四、采用自定义登陆的逻辑处理器

  • AuthenticationProvider实现类

@Component
public class AuthenticationProviderImpl implements AuthenticationProvider {

    private static final Logger log = LoggerFactory.getLogger(AuthenticationProviderImpl.class);

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String userName = authentication.getName();
        String password = authentication.getCredentials().toString();
        log.info("userName:"+userName+" password:"+password);
        UserDetails userDetails = userDetailsService.loadUserByUsername(userName);
        return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
    }

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


@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)//注解验证权限
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;
    @Autowired
    private AuthenticationProviderImpl authenticationProvider;
    @Autowired
    private AccessDeniedHandlerImpl accessDeniedHandler;
    @Autowired
    private AuthenticationEntryPointImpl authenticationEntryPoint;
    @Autowired
    private AuthenticationFailureHandlerImpl authenticationFailureHandler;
    @Autowired
    private AuthenticationSuccessHandlerImpl authenticationSuccessHandler;
    @Autowired
    private LogoutSuccessHandlerImpl logoutSuccessHandler;

    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // 关闭csrf防护
                .csrf().disable()
                .headers().frameOptions().disable()
                .and();
        http
                .httpBasic()
                .authenticationEntryPoint(authenticationEntryPoint)
                .and()
                //登录处理
                .formLogin() //表单方式
                .loginPage("/login")
                .loginProcessingUrl("/login/submit")
                .defaultSuccessUrl("/index") //成功登陆后跳转页面
                .failureHandler(authenticationFailureHandler)
                .successHandler(authenticationSuccessHandler)
                .permitAll()
                .and();
        http.exceptionHandling()
                .accessDeniedHandler(accessDeniedHandler)
                .and();
        http.logout()
                .logoutSuccessHandler(logoutSuccessHandler)
                .and();
        http
                .authorizeRequests() // 授权配置
                //无需权限访问
                .antMatchers( "/css/**", "/error404").permitAll()
                //其他接口需要登录后才能访问
                .anyRequest().authenticated()
                .and();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 1、默认的登陆处理器,
        //auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
        // 2、自己实现登陆逻辑处理
        auth.authenticationProvider(authenticationProvider);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}


五、到此登陆逻辑就完成了,下面是接口权限校验注解

  • 按照官方文档可以实现复杂的使用,此处就简单校验了是否拥有权限
@GetMapping(value = {"/index","/"})
    @PreAuthorize(value = "hasAuthority('index')")
    public String index(){
        return "index page";
    }

    @GetMapping(value = {"/user"})
    @PreAuthorize(value = "hasAuthority('user')")
    public Object user(){
        return SecurityContextHolder.getContext().getAuthentication();
    }

    @GetMapping(value = {"/sessionId"})
    public String sessionId(HttpServletRequest request){
        return "sessionId="+request.getSession().getId();
    }

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!