IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> SpringSecurity代码核心 -> 正文阅读

[Java知识库]SpringSecurity代码核心

认证过滤器:通过attemptAuthentication方法进行认证,获取请求的账号密码为user对象,通过AuthenticationManager的authenticate方法,使用自己编写的UserDetailService进行认证,认证成功则调用successfulAuthentication方法,将用户的权限存储在redis中,返回token

public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {

    private RedisTemplate redisTemplate;
    private AuthenticationManager authenticationManager;
    private TokenManager tokenManager;

    public TokenLoginFilter(TokenManager tokenManager, RedisTemplate redisTemplate, AuthenticationManager authenticationManager) {
        this.redisTemplate = redisTemplate;
        this.authenticationManager = authenticationManager;
        this.tokenManager = tokenManager;
        this.setPostOnly(false);//只接受POST请求(否则调用认证失败方法)
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/acl/login", "POST"));
    }

    //获取表单提交用户名密码
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        //获取表单数据
        User user = null;
        try {
            user = new ObjectMapper().readValue(request.getInputStream(), User.class);
            return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), new ArrayList<>()));
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException();
        }


    }

    //认证成功
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        //认证成功后用户信息
        SecurityUser user = (SecurityUser) authResult.getPrincipal();

        String username = tokenManager.generateToken(user.getCurrentUserInfo().getUsername());
        String token = tokenManager.generateToken(username);
        redisTemplate.opsForValue().set(username, user.getPermissionValueList());

        ResponseUtil.out(response, R.ok().data("token", token));
    }

    //认证失败

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        ResponseUtil.out(response, R.error());
    }
}


Security配置类

public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter {

    private RedisTemplate redisTemplate;

    private TokenManager tokenManager;

    private DefaultPasswordEncoder defaultPasswordEncoder;

    private UserDetailsService userDetailsService;

    @Autowired
    public TokenWebSecurityConfig(RedisTemplate redisTemplate,TokenManager tokenManager,DefaultPasswordEncoder defaultPasswordEncoder, UserDetailsService userDetailsService){
        this.redisTemplate = redisTemplate;
        this.tokenManager = tokenManager;
        this.defaultPasswordEncoder = defaultPasswordEncoder;
        this.userDetailsService = userDetailsService;
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling()
                .authenticationEntryPoint(new UnauthEntryPoin())//没有权限访问
                .and().csrf().disable()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and().logout().logoutUrl("/admin/acl/index/logout")
                .addLogoutHandler(new TokenLogoutHandler(tokenManager,redisTemplate))
                .and().addFilter(new TokenAuthFilter(authenticationManager() ,redisTemplate,tokenManager))
                .addFilter(new TokenLoginFilter(tokenManager,redisTemplate,authenticationManager())).httpBasic();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(defaultPasswordEncoder);
    }


    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/api/**");//不进行认证的路径,可以直接访问
    }
}

密码编码译码器

@Component
public class DefaultPasswordEncoder implements PasswordEncoder {


    public DefaultPasswordEncoder(){
        this(-1);
    }

    public DefaultPasswordEncoder(int i){

    }

    @Override
    public String encode(CharSequence var1) {

        return MD5.encrypt(var1.toString());
    }


    //和密码比对
    //var1为密码,var2位加密后的密码(MD5是不可逆的)
    @Override
    public boolean matches(CharSequence var1, String var2) {
        return var2.equals(MD5.encrypt(var1.toString()));
    }
}

Token管理器

@Component
public class TokenManager {
    //有效时长
    private long expiraTime = 24*60;

    //编制密钥
    private String tokenSecretKey = "123456";


    //根据用户名生成token
    public String generateToken(String username){
        String token = Jwts.builder()
                .setSubject(username)
                .setExpiration(new Date(System.currentTimeMillis()+expiraTime))
                .signWith(SignatureAlgorithm.ES512,tokenSecretKey)
                .compressWith(CompressionCodecs.GZIP).compact();

        return token;
    }

    //根据token获取用户信息
    public String getUserInfoByToken(String token){
        String userInfo = Jwts.parser().setSigningKey(tokenSecretKey)
                .parseClaimsJws(token).getBody()
                .getSubject();

        return userInfo;
    }

    public void removeToken(String token){

    }
}

无权访问入口

public class UnauthEntryPoin implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        ResponseUtil.out(httpServletResponse, R.error());
    }
}

登出处理器:获取请求头携带的token,移除token,redis删除token对应的用户

public class TokenLogoutHandler implements LogoutHandler {


    private TokenManager tokenManager;


    private RedisTemplate redisTemplate;

    public TokenLogoutHandler(TokenManager tokenManager,RedisTemplate redisTemplate){
        this.redisTemplate = redisTemplate;
        this.tokenManager = tokenManager;
    }

    @Override
    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
        //从header获取token
        String token = request.getHeader("token");


//        token不为空   移除token
        if(null != token){
            tokenManager.removeToken(token);

            String userInfo = tokenManager.getUserInfoByToken(token);
            redisTemplate.delete(userInfo);
        }
        ResponseUtil.out(response, R.ok());
    }
}

授权过滤器:根据请求头的token获取权限列表,生成一个授权对象,如果对象不为空,则放在上下文对象SecurityContext中,他是全局生效。对于@Security放在控制器方法的注解,会根据权限进行验证

public class TokenAuthFilter extends BasicAuthenticationFilter {

    private RedisTemplate redisTemplate;

    private TokenManager tokenManager;


    public TokenAuthFilter(AuthenticationManager authenticationManager, RedisTemplate redisTemplate, TokenManager tokenManager) {
        super(authenticationManager);
        this.redisTemplate = redisTemplate;
        this.tokenManager = tokenManager;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        //获取当前认证的用户权限信息
        UsernamePasswordAuthenticationToken authentication = getAuthentication(request);
       //如果有权限信息,就放在权限上下文
        if(authentication != null){
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        //放行
        chain.doFilter(request,response);
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        String token = request.getHeader("token");
        if (token != null) {
            //从token获取用户名
            String username = tokenManager.getUserInfoByToken(token);

            //从redis获取权限列表
            List<String> permissionValueList = (List<String>) redisTemplate.opsForValue().get(username);
            Collection<GrantedAuthority> authrity = new ArrayList<>();
            for (String s : permissionValueList) {
                authrity.add(new SimpleGrantedAuthority(s));
            }

            return new UsernamePasswordAuthenticationToken(username,token,authrity);
        }
        return null;
    }
}

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-04-18 17:27:33  更:2022-04-18 17:28:10 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 4:52:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码