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知识库 -> Spring Security认证授权-权限验证使用教程(二) -> 正文阅读

[Java知识库]Spring Security认证授权-权限验证使用教程(二)

作者:color:#fe2c24;

Security 项目案例

1.自定义Spring Security 核心配置类

TokenWebSecurityConfig.class

package com.wechat.web.conf.security;

import com.wechat.web.persistence.service.IAdminUserService;
import com.wechat.web.persistence.service.IWxUserService;
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.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.core.userdetails.UserDetailsService;


/**
 *  secutiry 核心配置类
 * @program: webSite
 * @description
 * @author: Joker
 * @create: 2021-06-25 16:59
 **/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter {

    private TokenManager tokenManager;
//    private RedisTemplate redisTemplate;

    private DefaultPasswordEncoder defaultPasswordEncoder;
    private UserDetailsService userDetailsService;
    private TokenLoginFilter tokenLoginFilter;
    private IWxUserService wxUserService;
    private IAdminUserService adminUserService;

    @Autowired
    public TokenWebSecurityConfig(DefaultPasswordEncoder defaultPasswordEncoder, TokenManager tokenManager, UserDetailsService userDetailsService,IWxUserService wxUserService,IAdminUserService adminUserService){
        this.defaultPasswordEncoder = defaultPasswordEncoder;
        this.tokenManager = tokenManager;
//        this.redisTemplate = redisTemplate;
        this.userDetailsService = userDetailsService;
        this.wxUserService = wxUserService;
        this.adminUserService = adminUserService;
        this.tokenLoginFilter = new TokenLoginFilter(tokenManager,wxUserService,adminUserService);
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.

                // 任何尚未匹配的URL都需要对用户进行身份验证

                formLogin().loginProcessingUrl("/wx-user/login")
                //退出路径
                .and().logout().logoutUrl("/wx-user/logOut")
                .addLogoutHandler(new TokenLogoutHandler(tokenManager))

//                .exceptionHandling()


                .and().cors().and().csrf().disable()

//                .authorizeRequests()
                // 定义了默认允许访问的资源(不需要认证)
                .exceptionHandling()
                //没有权限访问
                .accessDeniedHandler(new AccessDeniedAuthenticationHandler())
                .authenticationEntryPoint(new UnauthEntryPoint())
//        authenticationManager()
                //认证过滤器
                .and()
                .addFilter(new TokenLoginFilter(tokenManager,wxUserService,adminUserService))
                //授权过滤器
                .addFilter(new TokenAuthFilter(authenticationManager(),tokenManager))
                .authorizeRequests()
                .antMatchers(

                ).permitAll()
                .anyRequest().authenticated()
                .and()
                .httpBasic();
    }

    //调用userDateilsService和密码处理
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        System.out.println("处理");
        auth.authenticationProvider(tokenLoginFilter);
//                userDetailsService(userDetailsService)
//                .passwordEncoder(defaultPasswordEncoder);
    }

    //不进行认证的路径,可以直接进行访问
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/api/**",
//                "/**",
                "/swagger-**/**",
                "favicon.ico",
                "/v2/api-docs",
                "/webjars/**",
                "/error",
                "/wx-user/wxLogin",
                "/wx-user/callBack",
                "/wx-user/reply",
                "/web/v1/**"
//                "/MP_verify_kAZg9REXJwINtdRC.txt"

                );
    }
}

2.自定义登录认证过滤器

TokenLoginFilter.class

package com.wechat.web.conf.security;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wechat.web.persistence.domain.AdminUserBean;
import com.wechat.web.persistence.domain.WxUserBean;
import com.wechat.web.persistence.service.IAdminUserService;
import com.wechat.web.persistence.service.IWxUserService;
import com.wechat.web.tool.beanUtil.BeanMapper;
import com.wechat.web.tool.enums.Msg;
import com.wechat.web.tool.result.Result;
import com.wechat.web.tool.unifyUser.SecurityUser;
import com.wechat.web.tool.unifyUser.ServletUtils;
import com.wechat.web.tool.unifyUser.UnifyUser;
import com.wechat.web.persistence.vo.login.LoginVO;
import org.springframework.security.authentication.AuthenticationManager;
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.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

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

/**
 *  登录认证过滤器
 * @program: webSite
 * @description
 * @author: Joker
 * @create: 2021-06-25 16:20
 **/
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter implements AuthenticationProvider {


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

    private IWxUserService wxUserService;
    private IAdminUserService adminUserService;

    public TokenLoginFilter(TokenManager tokenManager,IWxUserService wxUserService,IAdminUserService adminUserService){
//        this.authenticationManager = authenticationManager;
        this.tokenManager = tokenManager;
        this.wxUserService = wxUserService;
        this.adminUserService = adminUserService;
//        this.redisTemplate = redisTemplate;
        this.setPostOnly(false);
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/wx-user/login","POST"));
    }

    /***
     *  授权 及 认证 处理方法
     * @param authentication
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        //1.获取放入的登录信息
        WxLoginAuthenticationToken token = (WxLoginAuthenticationToken)authentication;
        Object principal = token.getPrincipal();
        LoginVO loginVO = (LoginVO)principal;
        System.out.println("登录授权信息对象:"+loginVO.toString());

        // type == 1 微信授权登录
        if(loginVO.getType()==1){
            //2.根据openId查询数据库用户
            WxUserBean serviceOpenId = wxUserService.getOpenId(loginVO.getOpenId());
            //3. 数据库未查询到用户信息则为注册
            if(serviceOpenId==null){
                serviceOpenId = wxUserService.saveWxUser(loginVO);
            }
            // 4. 返回登录授权处理信息
            return new WxLoginAuthenticationToken(serviceOpenId,loginVO.getType());
        }else { // 后台管理登录
            System.out.println(loginVO.getAccount());
            System.out.println(loginVO.getPassword());
            // 根据账号密码查询管理员
            AdminUserBean adminUserBean = adminUserService.getAccount(loginVO.getAccount(), loginVO.getPassword());
            if(adminUserBean!=null){
                // 4. 返回管理员信息
                return new WxLoginAuthenticationToken(adminUserBean,loginVO.getType());
            }
            //用户名或密码错误
            return new WxLoginAuthenticationToken("用户名或者密码错误",3);
        }
    }

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



    //1.获取表单提交的用户名和密码
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {

        try {
            //1.获取表单数据对象
            LoginVO Login = new ObjectMapper().readValue(request.getInputStream(), LoginVO.class);
            System.out.println("表单提交的信息:"+Login.toString());

            //2.将数据交给自定义登录授权 WxLoginAuthenticationToken
            return  this.authenticate(new WxLoginAuthenticationToken(Login,Login.getType()));

        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException();
        }
    }


    //2.认证成功调用的方法
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult){

        //1.获取登录认证成功后的wxUserBean信息
        System.out.println("登录认证成功wxUser:"+authResult.getPrincipal().toString());

        WxLoginAuthenticationToken wxLoginAuthenticationToken = (WxLoginAuthenticationToken)authResult;
        Object principal = wxLoginAuthenticationToken.getPrincipal();
        Integer type = wxLoginAuthenticationToken.getType();

        //2.将wxUserBean 转换成 UnifyUser
        UnifyUser unifyUser = null;
        if(type==1){
            WxUserBean wxUserBean = (WxUserBean)principal;
            unifyUser = BeanMapper.map(wxUserBean, UnifyUser.class);
        }else if (type==2){
            AdminUserBean adminUserBean = (AdminUserBean)principal;
            unifyUser = BeanMapper.map(adminUserBean, UnifyUser.class);
        }else {
            ServletUtils.responseJson(response, Result.error(Msg.E40002));
            return;
        }
//        SecurityUser user = new SecurityUser();
//        user.setCurrentUserInfo(wxUserBean);
//        UnifyUser unifyUser = BeanMapper.map(user.getCurrentUserInfo(), UnifyUser.class);
//        unifyUser.setRoleCodes(user.getPermissionValueList());


        System.out.println("登录认证成功unifyUser:"+unifyUser.toString());

        //3.将unifyUser 对象转换成JsonString
        String jsonString = JSONObject.toJSONString(unifyUser);

        //4.根据认证成功用户信息json字符串生成token
        String token = tokenManager.createToken(jsonString);

        //5.将token存入响应返回头
        response.setHeader("token",token);

        //6.将token放入unifyUser对象
        unifyUser.setToken(token);

        ServletUtils.responseJson(response, Result.success(unifyUser));
    }



    //3.认证失败调用的方法
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed){

        //1.返回 登陆失败、用户名或密码错误
        System.out.println("认证失败调用的方法");
        ServletUtils.responseJson(response, Result.error(Msg.E40002));
    }
}

3.自定义请求认证授权过滤器

TokenAuthFilter.class

package com.wechat.web.conf.security;


import com.alibaba.fastjson.JSONObject;
import com.wechat.web.tool.enums.Msg;
import com.wechat.web.tool.result.Result;
import com.wechat.web.tool.unifyUser.ServletUtils;
import com.wechat.web.tool.unifyUser.UnifyUser;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 *  请求认证相关 授权过滤
 *
 * @program: webSite
 * @description
 * @author: Joker
 * @create: 2021-06-25 16:42
 **/
public class TokenAuthFilter extends BasicAuthenticationFilter {

    private TokenManager tokenManager;
//    private RedisTemplate redisTemplate;

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



    //1.接收请求、进行token认证
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

        //1.获取当前认证成功用户权限信息
        UsernamePasswordAuthenticationToken authRequest = getAuthentication(request,response);
        System.out.println(authRequest);
        //2.判断如果有权限信息,放到权限上下文中
        if(authRequest!=null){
            //3.存储当前用户对象
            SecurityContextHolder.getContext().setAuthentication(authRequest);
            //4.放行
            chain.doFilter(request,response);
        }else{
            //5.未获取到用户信息
            ServletUtils.responseJson(response, Result.error(Msg.F00001));
        }
    }

    // 2.获取当前认证成功用户权限信息
    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request, HttpServletResponse response){
        System.out.println("进入请求认证");
        //1.从请求头head中获取token
        String token = request.getHeader("token");
        System.out.println("从请求头head中获取token:"+token);

        if(token!=null){
            //2.根据token字符串得到用户信息
            String userInfo = tokenManager.getUserInfoFromToken(response,token);
            //3.token解析后为空则返回null
            if(userInfo==null){
                return null;
            }
            System.out.println("token获取到的用户信息:"+userInfo);
            //3.JWT 解析用户信息string转换成UnifyUser对象
            UnifyUser users = JSONObject.parseObject(userInfo, UnifyUser.class);
            users.setToken(token);

            //4.将UnifyUser 中 权限列表 添加到 authorities中
            List<String> permissionValueList = users.getRoleCodes();
            Collection<GrantedAuthority> authorities  = new ArrayList<>();
            if(permissionValueList!=null){
                for (String  permissionValue:permissionValueList){
                    SimpleGrantedAuthority auth = new SimpleGrantedAuthority(permissionValue);
                    authorities.add(auth);
                }
            }
            System.out.println("UnifyUser内容:"+users.toString());
            return new UsernamePasswordAuthenticationToken(users,token,authorities);
        }
        // 5.请求中未包含token信息、返回前端请登录
        ServletUtils.responseJson(response, Result.error(Msg.E40001));
        return null;
    }


}

4.自定义退出登录处理器

TokenLogoutHandler.class

package com.wechat.web.conf.security;


import com.wechat.web.tool.enums.Msg;
import com.wechat.web.tool.result.Result;
import com.wechat.web.tool.unifyUser.ServletUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *  退出登录处理器
 *
 * @program: webSite
 * @description
 * @author: Joker
 * @create: 2021-06-25 16:04
 **/
public class TokenLogoutHandler implements LogoutHandler {


    private TokenManager tokenManager;
//    private RedisTemplate redisTemplate;

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


    @Override
    public void logout(HttpServletRequest request, HttpServletResponse httpServletResponse, Authentication authentication) {

        //1.从请求头hread里获取token
        String token = request.getHeader("token");
        System.out.println("退出处理获取的hread中token:"+token);
        // 2.token不为空
        if(token!=null){
            // 2.1从token中获取用户基本信息
            String userJson = tokenManager.getUserInfoFromToken(httpServletResponse,token);
            if(userJson==null){
                // 2.2 登陆信息已过期,请重新登陆!
                ServletUtils.responseJson(httpServletResponse, Result.error(Msg.F10006));
            }
            // 2.3 调用JWT方法、移除token信息
            tokenManager.removeToken(token);

            // 3.注销成功 token信息已删除
            ServletUtils.responseJson(httpServletResponse, Result.error(Msg.F10003));
        }else {

            // 4.注销失败! 未在请求头中获取到token
            ServletUtils.responseJson(httpServletResponse, Result.error(Msg.F10004));
        }

    }
}

5.自定义权限验证过滤器

UnauthEntryPoint.class

package com.wechat.web.conf.security;


import com.wechat.web.tool.enums.Msg;
import com.wechat.web.tool.result.Result;
import com.wechat.web.tool.unifyUser.ServletUtils;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *  权限验证过滤器   AuthenticationEntryPoint 该类用来统一处理 AuthenticationException 异常
 * @program: webSite
 * @description
 * @author: Joker
 * @create: 2021-06-25 17:09
 **/
public class UnauthEntryPoint implements AuthenticationEntryPoint {


    //1.无权限访问
    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e){
        // 返回信息 访问失败,无权限进行访问!
        System.out.println("访问失败,无权限进行访问!");
        ServletUtils.responseJson(httpServletResponse, Result.error(Msg.F10005));
    }
}

6.自定义异常处过滤器

AccessDeniedAuthenticationHandler.class

package com.wechat.web.conf.security;


import com.wechat.web.tool.enums.Msg;
import com.wechat.web.tool.result.Result;
import com.wechat.web.tool.unifyUser.ServletUtils;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;

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

/**
 *
 *   AccessDeniedHandler 该类用来统一处理 AccessDeniedException 异常
 * @program: webSite
 * @description
 * @author: Joker
 * @create: 2021-06-30 10:06
 **/
public class AccessDeniedAuthenticationHandler implements AccessDeniedHandler {

    public AccessDeniedAuthenticationHandler() {
    }


    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
        System.out.println("无权限访问");
        ServletUtils.responseJson(httpServletResponse, Result.error(Msg.F10005));
    }
}

7.自定义微信授权登录

WxLoginAuthenticationToken.class

package com.wechat.web.conf.security;

import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;

import java.util.Collection;

/**
 *  自定义登录授权 WxLoginAuthenticationToken
 * @program: webSite
 * @description
 * @author: Joker
 * @create: 2021-06-25 16:20
 **/
public class WxLoginAuthenticationToken extends AbstractAuthenticationToken {


    private static final long serialVersionUID = 510L;
    private final Object principal;
    private Object credentials;

    // 1:微信公众号授权登录  2:后台管理界面登录
    private Integer type;

    public WxLoginAuthenticationToken(Object principal,Integer type) {
        super((Collection)null);
        this.principal = principal;
        this.type = type;
//        this.credentials = credentials;
        this.setAuthenticated(false);
    }

    public WxLoginAuthenticationToken(Object principal, Object credentials) {
        super((Collection)null);
        this.principal = principal;
        this.credentials = credentials;
        this.setAuthenticated(false);
    }

    public WxLoginAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
        super.setAuthenticated(true);
    }

    public Object getCredentials() {
        return this.credentials;
    }

    public Object getPrincipal() {
        return this.principal;
    }

    public Integer getType() {
        return type;
    }

    public void setType(Integer type) {
        this.type = type;
    }

    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        if (isAuthenticated) {
            throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
        } else {
            super.setAuthenticated(false);
        }
    }

    public void eraseCredentials() {
        super.eraseCredentials();
        this.credentials = null;
    }

    @Override
    public String toString() {
        return "WxLoginAuthenticationToken{" +
                "principal=" + principal +
                ", credentials=" + credentials +
                ", type=" + type +
                '}';
    }
}

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-15 11:30:57  更:2022-05-15 11:32:14 
 
开发: 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/23 22:34:43-

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