微服务迁移记(五):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集成
待续
六、权限管理
待续