文档章节

springboot security 安全机制

o
 osc_fmg49rzg
发布于 2019/03/21 11:32
字数 1497
阅读 35
收藏 0

行业解决方案、产品招募中!想赚钱就来传!>>>

springboot security 安全机制

 

认证流程:

1、由认证配置WebSecurityConfigurerAdapter的configure(HttpSecurity http)方法进入,添加拦截器addFilterBefore
2、进入拦截器AbstractAuthenticationProcessingFilter的attemptAuthentication方法,指定认证对象AbstractAuthenticationToken
3、进入认证逻辑AuthenticationProvider,根据supports的断定对认证的目标对象指定对哪个拦截器进行认证,进入具体的认证逻辑方法authenticate
4、认证结果:认证成功后进入拦截器的successfulAuthentication方法;认证失败后进入拦截器的unsuccessfulAuthentication方法
5、对认证结果进行处理
  a.认证成功的逻辑:进入SimpleUrlAuthenticationSuccessHandler的onAuthenticationSuccess方法
  b.认证失败的逻辑:进入SimpleUrlAuthenticationFailureHandler的onAuthenticationFailure方法
6、返回结果给页面,将数据封装在ObjectMapper对象中,将会以文本形式返回给客户端(页面)

 

 代码块

自定义认证配置,实现WebSecurityConfigurerAdapter 

package com.travelsky.config;

import com.travelsky.auto.login.BeforeLoginFilter;
import com.travelsky.auto.login.LoginProvider;
import com.travelsky.auto.login.OnFailureLogin;
import com.travelsky.auto.token.OnFailureToken;
import com.travelsky.auto.token.TokenFilter;
import com.travelsky.auto.token.TokenProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * 认证配置
 */
@Configuration
public class WebSecurityConfigurer  extends WebSecurityConfigurerAdapter {

    /**
     * 认证成功处理
     */
    @Autowired
    private SimpleUrlAuthenticationSuccessHandler successHandler;

    /**
     * 登录认证失败后处理
     */
    @Autowired
    private OnFailureLogin failureHandler;

    /**
     * token认证失败后处理
     */
    @Autowired
    private OnFailureToken onFailureToken;

    /**
     * 登录认证逻辑
     */
    @Autowired
    private LoginProvider loginProvider;

    /**
     * token认证逻辑
     */
    @Autowired
    private TokenProvider tokenProvider;

    /**
     * 配置请求权限
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                // 允许登录路径通过
                     .antMatchers("/login").permitAll()
                // 允许业务路径通过
                     .antMatchers("/**").permitAll()
                .and()
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .csrf().disable()
                // 添加拦截器
                     .addFilterBefore(getLoginFilter(), UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(getTokenFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    /**
     * 登录拦截器
     * @return
     * @throws Exception
     */
    private AbstractAuthenticationProcessingFilter getLoginFilter() throws Exception {
        BeforeLoginFilter beforeLoginFilter = new BeforeLoginFilter("/login", successHandler, failureHandler);
        beforeLoginFilter.setAuthenticationManager(super.authenticationManager());
        return beforeLoginFilter;
    }

    /**
     * token拦截器
     * @return
     * @throws Exception
     */
    private AbstractAuthenticationProcessingFilter getTokenFilter() throws Exception {
        TokenFilter tokenFilter = new TokenFilter("/**", onFailureToken);
        tokenFilter.setAuthenticationManager(super.authenticationManager());
        return tokenFilter;
    }

    /**
     * 配置认证逻辑列表,按顺序进行认证
     * @param auth
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(loginProvider);
        auth.authenticationProvider(tokenProvider);
    }
}

 

 

自定义拦截器,继承AbstractAuthenticationProcessingFilter

package com.travelsky.auto.login;

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

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

/**
 * 登录自定义拦截器,继承AbstractAuthenticationProcessingFilter
 */
@Slf4j
public class BeforeLoginFilter extends AbstractAuthenticationProcessingFilter {

    /**
     *认证成功的处理对象
     */
    private AuthenticationSuccessHandler successHandler;

    /**
     * 认证失败的处理对象
     */
    private AuthenticationFailureHandler failureHandler;

    public BeforeLoginFilter(String defaultFilterProcessesUrl, AuthenticationSuccessHandler successHandler, AuthenticationFailureHandler failureHandler) {
        super(defaultFilterProcessesUrl);
        this.successHandler = successHandler;
        this.failureHandler = failureHandler;
    }

    /**
     * 过滤器处理逻辑
     * @param request
     * @param response
     * @return
     * @throws AuthenticationException
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        log.info("进入登录过滤器");
        String userName = request.getParameter("userName");
        String password = request.getParameter("password");
        LoginInfo loginInfo = new LoginInfo(null, userName, password);
        log.info("username = {}", userName);
        log.info("password = {}", password);

        // 返回指定的认证对象
           LoginAuthenticationToken loginAuthentication = new LoginAuthenticationToken(null, loginInfo, null);

        // 将来由认证逻辑AuthenticationProvider来处理,这里返回LoginAuthenticationToken对象,将来由AuthenticationProvider的supports方法相匹配的认证逻辑来处理
           return this.getAuthenticationManager().authenticate(loginAuthentication);
    }

    /**
     * 认证逻辑认证成功成功后会调用此方法
     * @param request
     * @param response
     * @param chain
     * @param authResult
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        successHandler.onAuthenticationSuccess(request, response, authResult);
    }

    /**
     * 认证逻辑认证失败后调用此方法
     * @param request
     * @param response
     * @param failed
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        failureHandler.onAuthenticationFailure(request, response, failed);
    }
}

 

自定义认证逻辑,继承AuthenticationProvider

package com.travelsky.auto.login;

import com.alibaba.fastjson.JSONObject;
import com.travelsky.pojo.MenuVO;
import com.travelsky.pojo.SysUserInfo;
import com.travelsky.service.SysUserInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 认证逻辑
 */
@Component
@Slf4j
public class LoginProvider implements AuthenticationProvider {

    @Autowired
    private SysUserInfoService userInfoService;


    /**
     * 认证逻辑,认证的目标对象由supports断定,supports断定的目标对象是LoginAuthenticationToken自定义认证对象
     * @param authentication
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        log.info("登录验证器,接收参数:{}", JSONObject.toJSONString(authentication));

        // Authentication的具体子类,可由supports断定,supports断定子类是LoginAuthenticationToken,因此可以强转
           final LoginAuthenticationToken loginAuthentication = (LoginAuthenticationToken) authentication;
        final LoginInfo loginInfo = loginAuthentication.getLoginInfo();
        final String userName = loginInfo.getUserName();
        final SysUserInfo userInfo = userInfoService.getByUserId(userName);
        if (userInfo.getPassword().equals(loginInfo.getPassword())) {
            final List<MenuVO> userInfoMenus = userInfoService.getUserInfoMenus(userInfo.getId());
            return new LoginAuthenticationToken(null, loginInfo, userInfoMenus);
        } else {
            log.error("登录验证失败");
            throw new AuthenticationServiceException("登录失败.........");
        }
    }

    /**
     * 指定对谁进行认证,这里指定对LoginAuthenticationToken自定义认证对象进行认证
     * @param authentication
     * @return
     */
    @Override
    public boolean supports(Class<?> authentication) {
        return LoginAuthenticationToken.class.isAssignableFrom(authentication);
    }
}

 

自定义认证成功的处理逻辑,继承SimpleUrlAuthenticationSuccessHandler

package com.travelsky.auto.login;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.travelsky.auto.token.TokenContent;
import com.travelsky.auto.token.TokenFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

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

/**
 * 自定义认证成功处理逻辑,继承SimpleUrlAuthenticationSuccessHandler类
 */
@Component
@Slf4j
public class OnSuccessfulLogin extends SimpleUrlAuthenticationSuccessHandler {

    /**
     * 返回页面的对象,可将对象转化为文本形式(json格式)
     */
    @Autowired
    private ObjectMapper objectMapper;

    /**
     * token工厂
     */
    @Autowired
    private TokenFactory tokenFactory;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        log.info("登录认证成功,传入参数:{}", JSONObject.toJSONString(authentication));
        // 配置响应编码格式为UTF-8
           response.setCharacterEncoding("UTF-8");
        // 配置返回格式为json
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);

        // Authentication的具体子类为LoginAuthenticationToken
           final LoginAuthenticationToken loginAuthenticationToken = (LoginAuthenticationToken) authentication;
        final TokenContent tokenContent = tokenFactory.createToken("token");
        JSONObject json = new JSONObject();
        json.put("code", "000000");
        json.put("message", "认证成功");
        json.put("claims", tokenContent.getClaims());
        json.put("token", tokenContent.getToken());
        json.put("menuList", loginAuthenticationToken.getUserInfoMenus());
        log.info("生产token:{}",tokenContent.getToken());

        // 将数据保存到objectMapper中,将会转化为文本格式,返回给页面
        objectMapper.writeValue(response.getWriter(), json);
    }
}

 

自定义认证失败逻辑,继承SimpleUrlAuthenticationFailureHandler

package com.travelsky.auto.login;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;

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

@Slf4j
@Component
public class OnFailureLogin extends SimpleUrlAuthenticationFailureHandler {

    @Autowired
    private ObjectMapper objectMapper;

    @Override

    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        log.info("登录认证失败,传入参数:{}", JSONObject.toJSONString(exception));
        response.setCharacterEncoding("UTF-8");
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        JSONObject json = new JSONObject();
        json.put("code", "999999");
        json.put("message", exception.getMessage());
        objectMapper.writeValue(response.getWriter(), json);
    }
}

 

 

 

自定义认证对象,继承AbstractAuthenticationToken

package com.travelsky.auto.login;

import com.travelsky.pojo.MenuVO;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;

import java.util.Collection;
import java.util.List;

/**
 * 自定义登录认证对象
 */
public class LoginAuthenticationToken extends AbstractAuthenticationToken {

    /**
     * 登录数据对象
     */
    private LoginInfo loginInfo;

    /**
     * 菜单数据对象
     */
    private List<MenuVO> userInfoMenus;

    LoginAuthenticationToken(Collection<? extends GrantedAuthority> authorities, LoginInfo loginInfo, List<MenuVO> userInfoMenus) {
        super(authorities);
        this.userInfoMenus = userInfoMenus;
        this.loginInfo = loginInfo;
    }

    @Override
    public Object getCredentials() {
        return loginInfo.getPassword();
    }

    @Override
    public Object getPrincipal() {
        return loginInfo.getUserName();
    }

    public LoginInfo getLoginInfo() {
        return loginInfo;
    }

    public List<MenuVO> getUserInfoMenus() {
        return userInfoMenus;
    }
}

 

自定义拦截器:继承AbstractAuthenticationProcessingFilter,重写attemptAuthentication(HttpServletRequest request, HttpServletResponse response) 方法,返回AbstractAuthenticationToken的子类,AbstractAuthenticationToken的子类可自己定义内容(例如:用户信息,token字符串,Claims),只要继承AbstractAuthenticationToken即可

自定义验证规则:实现AuthenticationProvider接口,authenticate方法参数Authentication与拦截器attemptAuthentication方法返回的是同一个对象,重写 authenticate(Authentication authentication),其中supports(Class<?> authentication)方法用来指定当前检验规则是针对哪个AbstractAuthenticationToken子类对象。springboot自带默认的登录验证是返回UsernamePasswordAuthenticationToken对象。

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
访问安全控制解决方案

本文是《轻量级 Java Web 框架架构设计》的系列博文。 今天想和大家简单的分享一下,在 Smart 中是如何做到访问安全控制的。也就是说,当没有登录或 Session 过期时所做的操作,会自动退回到...

黄勇
2013/11/03
3.3K
6
基于 ThinkPHP 的内容管理系统--歪酷CMS

歪酷网站管理系统(歪酷CMS)是一款基于THINKPHP框架开发的PHP+MYSQL网站建站程序,本程序实现了文章和栏目的批量动态管理,支持栏目无限分类,实现多管理员管理,程序辅助功能也基本实现了常见的文...

鲁大在线
2013/02/19
6.8K
1
硬实时操作系统--Raw OS

Raw-OS 起飞于2012年,Raw-OS志在制作中国人自己的最优秀硬实时操作系统。 Raw-OS 操作系统特性 内核最大关中断时间无限接近0us, s3c2440系统最大关中断时间实测0.8us。 支持idle任务级别的事...

jorya_txj
2013/03/19
6.1K
1
高效率的nio框架--nio java raptor

设计初衷是提供方便易用,且高效率的nio框架,一部分实现上参考了mina。还包括线程池,编解码,内存池等机制,以便于开发高性能tcp程序。 文档后续会慢慢的补上。 整体实现上尽量少的使用锁,...

齐楠
2012/12/12
3.3K
0
CUSLayout

CUSLayout为iOS下提供托管定位机制。系统提供的绝对定位方式极不方便使用,另外iPhone的4寸屏幕的出现和iPad令iOS开发者在布局需要花更多的时间,然而iOS6.0提供的AutoLayout机制令人失望,所...

JJMM
2013/05/03
653
0

没有更多内容

加载失败,请刷新页面

加载更多

Linux拜拜!微软给WSL加入GPU支持,Windows终于迎来命令行包管理工具

点击蓝字“ 大白技术控 ”关注我哟 加个“星标★”,每日良时,好文必达! 白交 发自 凹非寺 量子位 报道 | 公众号 QbitAI 看完昨晚微软Build大会,虽然开发者不能亲自到现场,但看到WSL更新...

大白技术控
05/25
0
0
GraphQL

网文、分享汇总 干货分享 | GraphQL 数据聚合层 http://www.sohu.com/a/235978606_205771 awesome-graphql https://github.com/chentsulin/awesome-graphql 一些graphql相关的java项目 周边项......

素雷
1分钟前
0
0
如何在jQuery中选择具有多个类的元素? - How can I select an element with multiple classes in jQuery?

问题: I want to select all the elements that have the two classes a and b . 我想选择具有两个类a和b所有元素。 <element class="a b"> So, only the elements that have both classe......

javail
24分钟前
5
0
MySql查询所有字段不为空值的数据及Mybatis的#号和$符的区别引起的问题

1.MySql查询所有字段不为空值的数据 搜了一上午搜不到,最后用Mybatis的foreach标签,先查询出表字段, SELECT COLUMN_NAMEFROM INFORMATION_SCHEMA.ColumnsWHERE table_name='lltest'...

不忘初心牢记使命
24分钟前
22
0
五分钟搞定WebRTC视频录制

WebRTC中文社区是一个为大家解决在使用WebRTC当中遇到问题所建立的社区,欢迎更多学习和使用WebRTC的人加入进来,一起建设。 视频录制 在之前的文章里我们提到过视频录制的两种方式:客户端录...

死磕音视频
31分钟前
13
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部