微服务迁移记(五):WEB层搭建(2)-SpringSecurity集成

一、redis搭建

二、WEB层主要依赖包

 

三、FeignClient通用接口

以上三项,参考《微服务迁移记(五):WEB层搭建(1)

 

接下来,集成SpringSecruity,实现用户登录。

总体思路为:自定义UserDetails、UserDetailsService,重载WebSecurityConfigurerAdapter实现自定义表单登录,将菜单和按钮权限也扔到SpringSecruity的Session里。

四、SpringSecurity集成

1. 自定义MyUserDetails,实现UserDetails接口

1)我在里面多定义了一个UserEntity实体,通过get方法可以拿到这个实体,实现前台的一些业务逻辑。

RoleTreefuncEntity是功能权限树,也扔到session里。

2)isAccountNonExpired、isAccountNonLocked、isCredentialsNonExpired、isEnabled这几个方法,因为我直接从用户表取 del_flag=0的用户,不判断用户禁用或过期等状态,都直接返回true了。

package com.zyproject.web.secrity;

import com.zyproject.entity.RoleTreefuncEntity;
import com.zyproject.entity.UserEntity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

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

/**
 * @program: zyproject
 * @description: 实现SpringSercrity UserDetails
 * @author: zhouyu(zhouyu629 # qq.com)
 * @create: 2020-02-12
 **/
public class MyUserDetails implements UserDetails {

    private UserEntity userEntity; //用户实体
    //将用户所有的角色菜单权限放到内存中,供校验使用
    private List<RoleTreefuncEntity> roleTreefuncEntities;

    public MyUserDetails(UserEntity userEntity,List<RoleTreefuncEntity> roleTreefuncEntities){
        this.userEntity = userEntity;
        this.roleTreefuncEntities = roleTreefuncEntities;
    }

    //获取用户真实姓名
    public String getRealName(){
        return userEntity.getUser_name();
    }

    //获取用户实体
    public UserEntity getUserEntity(){
        return this.userEntity;
    }

    //获取权限菜单
    public List<RoleTreefuncEntity> getTreefuncEntities(){return this.roleTreefuncEntities;}

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

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

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

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

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

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

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

 2. 自定义MyUserDetailsService接口,实现UserDetailsService接口

package com.zyproject.web.secrity;

import com.google.gson.Gson;
import com.zyproject.common.CodeEnum;
import com.zyproject.common.ResponseData;
import com.zyproject.entity.RoleTreefuncEntity;
import com.zyproject.entity.UserEntity;
import com.zyproject.web.service.TreeService;
import com.zyproject.web.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;

/**
 * @program: zyproject
 * @description: 实现SpringSecrity UserDetailService接口
 * @author: zhouyu(zhouyu629 # qq.com)
 * @create: 2020-02-12
 **/
@Service
public class MyUserDetailService implements UserDetailsService {
    @Autowired
    private UserService userService;
    @Autowired
    private TreeService treeService;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        ResponseData<UserEntity> userResult = userService.findByLoginname(s);
        UserEntity user = new UserEntity();
        if(userResult.getCode() == CodeEnum.SUCCESS.getCode()){
            user = userResult.getData(UserEntity.class);
            ResponseData rightResult = treeService.getRoleTreefuncByUserid(user.getUser_id());
            Gson gson = new Gson();
            List<RoleTreefuncEntity> roleTreefuncEntities = Arrays.asList(gson.fromJson(gson.toJson(rightResult.getData()),RoleTreefuncEntity[].class));
            return new MyUserDetails(user,roleTreefuncEntities);
        }else{
            throw new UsernameNotFoundException(s);
        }
    }
}

3. SecurityConfiguration配置

1) 覆写protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder),实现MD5密码校验

2) protected  void configure(HttpSecurity httpSecurity),实现自定义表单登录

package com.zyproject.web.secrity;

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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @program: zyproject
 * @description: SpringSercrity配置
 * @author: zhouyu(zhouyu629 # qq.com)
 * @create: 2020-02-12
 **/
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailService myUserDetailService;

    @Autowired
    private MyAuthenctiationFailureHandler myAuthenctiationFailureHandler;

    @Autowired
    private MyAuthenctiationSucessHandler myAuthenctiationSucessHandler;

    @Override
    protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception{
        authenticationManagerBuilder.userDetailsService(myUserDetailService).passwordEncoder(new PasswordEncoder() {
            @Override
            public String encode(CharSequence charSequence) {
                return MD5Util.encode((String)charSequence);
            }

            @Override
            public boolean matches(CharSequence charSequence, String s) {
                return s.equals(MD5Util.encode((String)charSequence));
            }
        });
    }


    @Override
    protected  void configure(HttpSecurity httpSecurity) throws Exception{
        httpSecurity.headers().frameOptions().disable();
        httpSecurity
                .authorizeRequests()
                .antMatchers("/manage/error","/manage/login/**","/manage/login-submit","/manage/images/**","/manage/js/**","/manage/css/**","/manage/fonts/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                //指定登录路径
                .loginPage("/manage/login")
                .loginProcessingUrl("/manage/login-submit") //表单请求的路径,貌似无用,已经在config里做密码校验了
                .failureHandler(myAuthenctiationFailureHandler)
                .successHandler(myAuthenctiationSucessHandler)
                .failureUrl("/manage/error?key=1002")
                .defaultSuccessUrl("/manage/index")
                .usernameParameter("username")
                .passwordParameter("password")
                //必须允许所有用户访问我们的登录页(例如未验证的用户,否则验证流程就会进入死循环)
                .permitAll()
                .and()
                .sessionManagement()
                .invalidSessionUrl("/manage/error?key=timeout");
        //默认都会产生一个hiden标签 里面有安全相关的验证 防止请求伪造 这边我们暂时不需要 可禁用掉
        httpSecurity.csrf().disable();
    }

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

 

五、FreeMarker集成

待续

六、权限管理

待续

posted on 2020-02-23 11:10  zhouyu  阅读(360)  评论(0编辑  收藏  举报

导航