SpringBoot和SpringCloud 使用 spring security 认证框架详解

上目录结构

//权限管理模块
// 1. 创建一个权限管理的子模块

//2. 引入相关依赖
//    <dependencies>
//<!--        自定义的模块 安全框架 security-->
//        <dependency>
//            <groupId>com.schoolWeb</groupId>
//            <artifactId>spring_security</artifactId>
//            <version>0.0.1-SNAPSHOT</version>
//        </dependency>
//        <dependency>
//            <groupId>com.alibaba</groupId>
//            <artifactId>fastjson</artifactId>
//        </dependency>
//    </dependencies>

//3. 创建一个 权限管理的模块 编写相对应的权限代码 代码比较固定 分享到git 上了
//主要是 菜单管理 角色管理 分配权限 等常用功能

//4. 创建一个 spring_security模块 放在了 common模块里了 他是公共的   代码比较固定 分享到git 上了
// Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。提供了完善的认证机制和方法级的授权功能
// 本质就是过滤器  filter
// 用于 用户认证 和用户授权 两部分
// 如果是基于Session 那么 Spring Security 会对cookie里的sessionid进行解析认证
// 如果是token 则会解析token 然后将当前请求加入到Spring Security 管理的权限信息里去
// 这个玩意 帮我们 取值 放值  帮我们 管理 token 或者 session  不需要我们 自己再去具体实现

// 如果系统的模块众多 每个模块都需要认证 用户根据用户密码进行认证 然后获取一系列的权限 并已用户名为key
// 权限为value的形式存入redis里 根据用户的header头部里的token, Spring Security 解析token 这样判断是否有请求权限

//5. 引入spring_security 的相关依赖
//   <dependencies>
//<!--        自定义的工具类-->
//        <dependency>
//            <groupId>com.schoolWeb</groupId>
//            <artifactId>common_utils</artifactId>
//            <version>0.0.1-SNAPSHOT</version>
//        </dependency>
//        <!-- Spring Security依赖 -->
//        <dependency>
//            <groupId>org.springframework.boot</groupId>
//            <artifactId>spring-boot-starter-security</artifactId>
//        </dependency>
//
//        <dependency>
//            <groupId>io.jsonwebtoken</groupId>
//            <artifactId>jjwt</artifactId>
//        </dependency>
//    </dependencies>

//6. 整合  spring security 框架 具体实现类

//7. 需要一个md5 和ResponseUtil 工具类  md5自行查找 
public class ResponseUtil {

    public static void out(HttpServletResponse response, R r) {
        ObjectMapper mapper = new ObjectMapper();
        response.setStatus(HttpStatus.OK.value());
        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        try {
            mapper.writeValue(response.getWriter(), r);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
//8. 需要配置核心配置类的退出地址  TokenWebSecurityConfig.java
@Configuration
@EnableWebSecurity   //开启权限控制
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter {

    private UserDetailsService userDetailsService;  // 自定义查询数据库 认证密码
    private TokenManager tokenManager;   //token 工具
    private DefaultPasswordEncoder defaultPasswordEncoder;  // 密码处理
    private RedisTemplate redisTemplate;  //  redis 处理

    @Autowired
    public TokenWebSecurityConfig(UserDetailsService userDetailsService, DefaultPasswordEncoder defaultPasswordEncoder,
                                  TokenManager tokenManager, RedisTemplate redisTemplate) {
        this.userDetailsService = userDetailsService;
        this.defaultPasswordEncoder = defaultPasswordEncoder;
        this.tokenManager = tokenManager;
        this.redisTemplate = redisTemplate;
    }

    /**
     * 配置设置
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling()
                .authenticationEntryPoint(new UnauthorizedEntryPoint())
                .and().csrf().disable()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and().logout()
                .logoutUrl("/admin/acl/index/logout")  // 设置退出地址 可随意设置
                .addLogoutHandler(new TokenLogoutHandler(tokenManager,redisTemplate)).and()
                .addFilter(new TokenLoginFilter(authenticationManager(), tokenManager, redisTemplate))
                .addFilter(new TokenAuthenticationFilter(authenticationManager(), tokenManager, redisTemplate)).httpBasic();
    }
    /**
     * 配置哪些请求不拦截  这个注意一下  要不 登录退出路径 有可能报错 404
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/api/**",
                "/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**"
        );
//        web.ignoring().antMatchers("/*/**"
//        );
    }

    /**
     * 密码处理
     * @param auth
     * @throws Exception
     */
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(defaultPasswordEncoder);
    }


//9. 实现 security提供的UserDetails 接口   SecurityUser.java
package com.school.security.entity;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.StringUtils;

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

/**
 * <p>
 * 安全认证用户详情信息
 * </p>
 *  相关实体类
 * @author qy
 * @since 2019-11-08
 */
@Data
@Slf4j
public class SecurityUser implements UserDetails {

    //当前登录用户
    private transient User currentUserInfo;

    //当前权限
    private List<String> permissionValueList;

    public SecurityUser() {
    }

    public SecurityUser(User user) {
        if (user != null) {
            this.currentUserInfo = user;
        }
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        for(String permissionValue : permissionValueList) {
            if(StringUtils.isEmpty(permissionValue)) continue;
            SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permissionValue);
            authorities.add(authority);
        }

        return authorities;
    }

    @Override
    public String getPassword() {
        return currentUserInfo.getPassword();
    }

    @Override
    public String getUsername() {
        return currentUserInfo.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}
//10. 登录校验认证过滤器  配置登录地址   TokenLoginFilter.java
/**
 * <p>
 * 登录过滤器,继承UsernamePasswordAuthenticationFilter,对用户名密码进行登录校验
 * </p>
 *  认证过滤器
 * @author qy
 * @since 2019-11-08
 */
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {

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

    public TokenLoginFilter(AuthenticationManager authenticationManager, TokenManager tokenManager, RedisTemplate redisTemplate) {
        this.authenticationManager = authenticationManager;
        this.tokenManager = tokenManager;
        this.redisTemplate = redisTemplate;
        this.setPostOnly(false);
        //这是登录地址 这个可以随便配置
        this.setRequiresAuthenticationRequestMatcher(
                new AntPathRequestMatcher("/admin/acl/login","POST"));
    }

    //得到 用户密码
    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
            throws AuthenticationException {
        try {
            User user = new ObjectMapper().readValue(req.getInputStream(), User.class);

            return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), new ArrayList<>()));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 登录成功  执行这个
     * @param req
     * @param res
     * @param chain
     * @param auth
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,
                                            Authentication auth) throws IOException, ServletException {
        SecurityUser user = (SecurityUser) auth.getPrincipal();
        //生成token 值
        String token = tokenManager.createToken(user.getCurrentUserInfo().getUsername());
        //根据用户名 把需要的 权限 放到 redis里
        redisTemplate.opsForValue().set(user.getCurrentUserInfo().getUsername(), user.getPermissionValueList());

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

    /**
     * 登录失败  执行这个
     * @param request
     * @param response
     * @param e
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                              AuthenticationException e) throws IOException, ServletException {
        ResponseUtil.out(response, R.error());
    }
}
//11. 授权过滤器
//12. 配置好  spring security 框架后 把这个 模块引入到某个的模块下( 就是步骤2 那个依赖)
// 比如 你 创建的 权限管理模块(acl) 这个模块下 都是权限授权和配置的操作
// 就可以引入到这个模块下 在这个模块具体使用spring security 下的功能


//13. 需要创建一个查询登录和用户权限的实现类 这个类 需要实现 spring security  下的 UserDetailsService 的接口
//  具体实现查询验证 用户登录 得到数据
// 注: 使用这种框架 思想为 :面向接口发开 或者 面向 spring security 开发
// 帮我们 实现了 验证 和授权登录 我们只需要 修改配置文件和 查询数据库数据 验证成功就行了

@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserService userService;

    @Autowired
    private PermissionService permissionService;

    /***
     * 根据账号获取用户信息
     * @param username:
     * @return: org.springframework.security.core.userdetails.UserDetails
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 从数据库中取出用户信息
        User user = userService.selectByUsername(username);

        // 判断用户是否存在
        if (null == user){
            //throw new UsernameNotFoundException("用户名不存在!");
        }
        // 返回UserDetails实现类
        com.school.security.entity.User curUser = new com.school.security.entity.User();
        BeanUtils.copyProperties(user,curUser);

       //获取权限
        List<String> authorities = permissionService.selectPermissionValueByUserId(user.getId());
        SecurityUser securityUser = new SecurityUser(curUser);
        securityUser.setPermissionValueList(authorities);
        return securityUser;
    }

}

// 使用了这个security 框架 实现登录后 自己开发的 登录 就无需再用了

github地址 

javaUtils/spring_security at main · Json870422471/javaUtils · GitHub

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Json____

您的鼓励是我创作的动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值