1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 用户与角色 Springboot Security Mybatis

用户与角色 Springboot Security Mybatis

时间:2018-12-01 03:02:58

相关推荐

用户与角色 Springboot Security Mybatis

安全认证与授权包括基于内存的认证,基于数据库的认证,高级配置

基于内存的认证是直接将用户名,密码,和用户与角色的url授权信息直接写在配置文件中,不需要读取数据库;

基于数据库的认证则是从数据库中直接读取用户名和密码,用户与角色的url授权信息仍然写在配置文件中;

高级配置中将这三条信息都存在数据库表中,为的是实现动态配置URL权限。

配置Security重点在于WebSecurityConfigurerAdapter

本文代码参考《Spring Boot Vue 全栈开发实战》王松 第十章

基于内存的认证

添加security依赖

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>自定义WebSecurityConfigurerAdapter

@Configurationpublic class MyWebSecurityConfig extends WebSecurityConfigurerAdapter { @Bean PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(10);//密码加密方式,BCrypt强哈希函数 } @Override//配置三名用户的的角色和密码,密码明文全是123 protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("root").password("$2a$10$yKbvsbp.mwbBmon34q3k/uZdXWbsh/8tDkChKqAbq/3xm7xC2VCTi").roles("ADMIN","DBA") .and() .withUser("admin").password("$2a$10$bvW.9j56BG0XPAA8icJQhuU4qUS7zT.lCayiqBry45HqJMajVV2JC").roles("ADMIN","USER") .and() .withUser("zhsh").password("$2a$10$UCu/YkcMgyvbumqM8unEeOSpDtCVAmCG0pncWS6CxcYSIGpQCcBtm").roles("USER"); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/admin/**").hasRole("ADMIN")//配置URL的角色要求 .antMatchers("/user/**").access("hasAnyRole("ADMIN","USER")") .antMatchers("/db/**").access("hasRole("ADMIN") and hasRole("DBA")") .anyRequest().authenticated() .and() .formLogin().loginProcessingUrl("/login")//开启表单登录 .usernameParameter("name").passwordParameter("passwd") .successHandler(new AuthenticationSuccessHandler() {//登录成功的一段JSON提示 @Override public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication auth) throws IOException { Object principal = auth.getPrincipal(); resp.setContentType("application/json;charset=utf-8"); PrintWriter out = resp.getWriter(); resp.setStatus(200); Map<String,Object> map = new HashMap<>(); map.put("status",200); map.put("msg",principal); ObjectMapper om = new ObjectMapper(); out.write(om.writeValueAsString(map)); out.flush(); out.close(); } }) .failureHandler(new AuthenticationFailureHandler() {//登录失败的一段JSON提示 @Override public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException e) throws IOException { resp.setContentType("application/json;charset=utf-8"); PrintWriter out = resp.getWriter(); resp.setStatus(401); Map<String,Object> map = new HashMap<>(); map.put("status",401); if(e instanceof LockedException){ map.put("msg","账号被锁定,登录失败!"); }else if(e instanceof BadCredentialsException){ map.put("msg","账户名或密码输入错误,登陆失败!"); }else if(e instanceof DisabledException){ map.put("msg","账号被禁用,登陆失败!"); }else if(e instanceof AccountExpiredException){ map.put("msg","账户已过期,登陆失败!"); }else if(e instanceof CredentialsExpiredException){ map.put("msg","密码已过期,登陆失败!"); }else{ map.put("msg","登录失败!"); } ObjectMapper om = new ObjectMapper(); out.write(om.writeValueAsString(map)); out.flush(); out.close(); } }) .permitAll() .and() .logout().logoutUrl("/logout")//开启注销登录 .clearAuthentication(true).invalidateHttpSession(true) .addLogoutHandler(new LogoutHandler() { @Override public void logout(HttpServletRequest req, HttpServletResponse resp, Authentication auth) { } }) .logoutSuccessHandler(new LogoutSuccessHandler() {//注销成功后的业务逻辑 @Override public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication auth) throws IOException { resp.sendRedirect("/loginPage"); } }) .and() .csrf().disable();//关闭csrf,跨站请求伪造 }}编写controller进行授权测试

@RestControllerpublic class HelloController { @GetMapping("/hello") public String hello(){ return "Hello!"; } @GetMapping("/admin/hello") public String admin(){ return "hello admin"; } @GetMapping("/user/hello") public String user(){ return "hello user"; } @GetMapping("/db/hello") public String dba(){ return "hello dba"; } @GetMapping("/loginPage") public ModelAndView loginPage(){ ModelAndView mv = new ModelAndView("index"); return mv; }}基于数据库的认证

设计数据表

user,role,user_role三张表

创建实体类

//因为UserDetails自带Boolean类型的isEnabled函数,会与@Data中的getEnabled有冲突,所以不能使用@Datapublic class User implements UserDetails { private Integer id; private String username; private String password; private Boolean enabled; private Boolean locked; private List<Role> roles; @Override public Collection<? extends GrantedAuthority> getAuthorities() { List<SimpleGrantedAuthority> authorities = new ArrayList<>(); for (Role role: roles){ authorities.add(new SimpleGrantedAuthority(role.getName())); } return authorities; } @Override public String getPassword() {return password;} @Override public String getUsername() { return username; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return !locked; } @Override public boolean isCredentialsNonExpired() {return true; } @Override public boolean isEnabled() { return enabled; } public void setEnabled(Boolean enabled) { this.enabled = enabled; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } public Boolean getLocked() { return locked; } public void setLocked(Boolean locked) {this.locked = locked; } public List<Role> getRoles() { return roles; } public void setRoles(List<Role> roles) { this.roles = roles; }}@Datapublic class Role { private Integer id; private String name; private String nameZh;}添加依赖与配置

<!--添加MyBatis依赖--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.1</version> </dependency> <!--添加mysql依赖--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--添加数据库连接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency>######## 数据库配置 ########spring.datasource.type=com.alibaba.druid.pool.DruidDataSourcespring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=UTCspring.datasource.username=rootspring.datasource.password=123spring.datasource.tomcat.max-idle=10spring.datasource.tomcat.max-active=50spring.datasource.tomcat.max-wait=10000spring.datasource.tomcat.initial-size=5# 采用隔离级别为读写提交spring.datasource.tomcat.default-transaction-isolation=2######### MyBatis配置 ######### 映射文件mybatis.mapper-locations=classpath:com/mhr/mhr/security/mapper/*.xml创建dao与mapper

//dao@Mapperpublic interface UserMapper { User loadUserByUsername(String username); List<Role> getUserRolesByUid(Integer id);}//mapper<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-////DTD Mapper 3.0//EN" "/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.mhr.mhr.security.dao.UserMapper"> <select resultType="com.mhr.mhr.security.pojo.User"> select * from user where username=#{username} </select> <select resultType="com.mhr.mhr.security.pojo.Role"> select * from role r,user_role ur where r.id=ur.rid and ur.uid=#{id} </select></mapper>创建service与controller

@Servicepublic class UserService implements UserDetailsService { @Autowired UserMapper userMapper; @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { User user = userMapper.loadUserByUsername(s); if (user==null){ throw new UsernameNotFoundException("账户不存在!"); } user.setRoles(userMapper.getUserRolesByUid(user.getId())); return user; }}@RestControllerpublic class UserController { @Autowired UserService userService; @GetMapping("/loadUserByUsername") public User loadUserByUsername(String username){ return (User) userService.loadUserByUsername(username); }}配置Spring Security

@Configurationpublic class WebSecurityConfig2 extends WebSecurityConfigurerAdapter { @Autowired UserService userService; @Bean PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } @Override //将UserService配置到AuthenticationManagerBuilder中,没有配置内存用户 protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userService); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/admin/**").hasRole("admin") .antMatchers("/user/**").hasRole("dba") .antMatchers("/db/**").hasRole("user") .anyRequest().authenticated() .and() .formLogin().loginProcessingUrl("/login").permitAll() .and() .csrf().disable(); }}高级配置

动态配置url权限

添加数据表

menu,menu_role

编写dao和mapper

//dao@Mapperpublic interface MenuMapper { List<Menu> getAllMenus();}//mapper<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-////DTD Mapper 3.0//EN" "/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.mhr.mhr.security.dao.MenuMapper"> <resultMap type="com.mhr.mhr.security.pojo.Menu"> <id property="id" column="id"/> <result property="pattern" column="pattern"/> <collection property="roles" ofType="com.mhr.mhr.security.pojo.Role"> <id property="id" column="id"/> <result property="name" column="rname"/> <result property="nameZh" column="rnameZh"/> </collection> </resultMap> <select resultMap="BaseResultMap"> select m.*,r.id as rid,r.name as rname,r.nameZh as rnameZh from menu m left join menu_role mr on m.`id`=mr.`mid` left join role r on mr.`rid`=r.`id` </select></mapper>自定义FilterInvocationSecurityMetadataSource

//主要实现接口中的getAttributes方法@Componentpublic class CustomFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { @Autowired MenuMapper menuMapper; AntPathMatcher antPathMatcher = new AntPathMatcher(); @Override public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException { String requestUrl = ((FilterInvocation)o).getRequestUrl(); List<Menu> allMenus = menuMapper.getAllMenus(); for (Menu menu: allMenus){ if(antPathMatcher.match(menu.getPattern(),requestUrl)){ //ant风格的url匹配 List<Role> roles = menu.getRoles(); String[] roleArr = new String[roles.size()]; for (int i = 0; i < roleArr.length; i ){ roleArr[i] = roles.get(i).getName(); } return SecurityConfig.createList(roleArr); } } return SecurityConfig.createList("ROLE_LOGIN"); } @Override public Collection<ConfigAttribute> getAllConfigAttributes() { return null; } @Override public boolean supports(Class<?> aClass) { return FilterInvocation.class.isAssignableFrom(aClass); }}自定义AccessDecisionManager

// 进行角色信息的比对@Componentpublic class CustomAccessDecisionManager implements AccessDecisionManager { @Override public void decide(Authentication auth, Object o, Collection<ConfigAttribute> ca){ Collection<? extends GrantedAuthority> auths = auth.getAuthorities(); for (ConfigAttribute configAttribute : ca){ if("ROLE_LOGIN".equals(configAttribute.getAttribute()) && auth instanceof UsernamePasswordAuthenticationToken){ return; } for (GrantedAuthority authority: auths){ if (configAttribute.getAttribute().equals(authority.getAuthority())){ return; } } } throw new AccessDeniedException("权限不足!"); } @Override public boolean supports(ConfigAttribute configAttribute) { return true; } @Override public boolean supports(Class<?> aClass) {return true; }}配置Spring Security

@Configurationpublic class WebSecurityConfig3 extends WebSecurityConfigurerAdapter { @Bean PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() { @Override public <O extends FilterSecurityInterceptor> O postProcess(O o) { o.setSecurityMetadataSource(cfisms()); o.setAccessDecisionManager(cadm()); return o; } }) .and() .formLogin().loginProcessingUrl("/login").permitAll() .and() .csrf().disable(); } @Bean CustomFilterInvocationSecurityMetadataSource cfisms(){ return new CustomFilterInvocationSecurityMetadataSource(); } @Bean CustomAccessDecisionManager cadm(){ return new CustomAccessDecisionManager(); }}来源:/content-4-453251.html

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。