继前几篇博客将用户、角色、权限信息都存在数据,实现管理权限到请求方法级别。感觉那种实现方式比较鸡肋,不太实用。所以今天说一下,官方推荐的注解方式控制权限到请求方法级别的实现。
官方推荐的方法是将用户、角色信息存在数据库,而角色和权限的对应关系,通过注解的方式写死在controller上。
废话不多说,上代码;
本文代码是基于博客 sPRingboot+mybatis+SpringSecurity 实现用户角色数据库管理(一) 的代码修改而来
1. 数据库设计

insert into SYS_USER (id,username, passWord) values (1,'admin', '$2a$10$YwbP2rm18bOWOrkJHybp5uTRHCpn5Rk8rGT6fogf0KdtNY7jzmebu');insert into SYS_USER (id,username, password) values (2,'abel', '$2a$10$/h0hVDo3A78lEHhsIckGz.nfXGgUFx2yB4bfy6o15RZi8VlZqt.PK');insert into SYS_ROLE(id,name) values(1,'ROLE_ADMIN');insert into SYS_ROLE(id,name) values(2,'ROLE_USER');2. 修改WebSecurityConfig 文件
此处使用了 BCryptPasswordEncoder 密码加密
使用了httpBasic 认证 : springSecurity 之 http Basic认证 (四)
package com.us.example.config;import com.us.example.security.CustomUserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Configuration;import org.springframework.http.HttpMethod;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.configuration.EnableWebSecurity;import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;/** * Created by yangyibo on 17/1/18. */@Configuration@EnableWebSecurity@EnableGlobalMethodSecurity(securedEnabled = true)// 控制权限注解public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CustomUserService customUserService; @Autowired protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(customUserService).passwordEncoder(new BCryptPasswordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .authorizeRequests() .antMatchers("/users/**") .authenticated() .antMatchers(HttpMethod.POST) .authenticated() .antMatchers(HttpMethod.PUT) .authenticated() .antMatchers(HttpMethod.DELETE) .authenticated() .antMatchers("/**") .permitAll() .and() .sessionManagement() .and() .httpBasic(); }}3. 修改SysUser 类实现 UserDetails接口
package com.us.example.domain;import com.fasterxml.jackson.annotation.JsonIgnore;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.userdetails.UserDetails;import java.util.Collection;import java.util.List;/** * Created by yangyibo on 17/1/17. */public class SysUser implements UserDetails { // implements UserDetails 用于登录时 @AuthenticationPrincipal 标签取值 private Integer id; private String username; @JsonIgnore private String password; private String rawPassword; @JsonIgnore private List<SysRole> roles; private List<? extends GrantedAuthority> authorities; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public List<SysRole> getRoles() { return roles; } public void setRoles(List<SysRole> roles) { this.roles = roles; } public String getRawPassword() { return rawPassword; } public void setRawPassword(String rawPassword) { this.rawPassword = rawPassword; } @JsonIgnore @Override public boolean isAccountNonExpired() { return true; } @JsonIgnore @Override public boolean isAccountNonLocked() { return true; } @JsonIgnore @Override public boolean isCredentialsNonExpired() { return true; } @JsonIgnore @Override public boolean isEnabled() { return true; } @JsonIgnore @Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } public void setGrantedAuthorities(List<? extends GrantedAuthority> authorities) { this.authorities = authorities; }}4. 修改 CustomUserService 类
package com.us.example.security;import com.us.example.dao.UserDao;import com.us.example.domain.SysRole;import com.us.example.domain.SysUser;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.core.authority.SimpleGrantedAuthority;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.ArrayList;import java.util.List;/** * Created by yangyibo on 17/1/18. */@Servicepublic class CustomUserService implements UserDetailsService { //自定义UserDetailsService 接口 @Autowired UserDao userDao; private static final org.slf4j.Logger logger = LoggerFactory.getLogger(CustomUserService.class); @Override public UserDetails loadUserByUsername(String username) { //重写loadUserByUsername 方法获得 userdetails 类型用户 SysUser user = userDao.findByUserName(username); if(user == null){ throw new UsernameNotFoundException("用户名不存在"); } List<SimpleGrantedAuthority> authorities = new ArrayList<>(); //用于添加用户的权限。只要把用户权限添加到authorities 就万事大吉。 for(SysRole role:user.getRoles()) { authorities.add(new SimpleGrantedAuthority(role.getName())); logger.info("loadUserByUsername: " + user); } user.setGrantedAuthorities(authorities); //用于登录时 @AuthenticationPrincipal 标签取值 return user; }}5. 添加登录controller
新建LoginController
package com.us.example.controller;import com.us.example.domain.SysUser;import org.springframework.security.core.annotation.AuthenticationPrincipal;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.RestController;/** * Created by yangyibo on 17/3/1. */@RestControllerpublic class LoginController { @RequestMapping(value = "/login") @ResponseBody public Object login(@AuthenticationPrincipal SysUser loginedUser, @RequestParam(name = "logout", required = false) String logout) { if (logout != null) { return null; } if (loginedUser != null) { return loginedUser; } return null; }}6. 修改 HomeController 添加权限控制
package com.us.example.controller;import com.us.example.domain.SysUser;import com.us.example.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.access.annotation.Secured;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.ResponseBody;/** * Created by yangyibo on 17/1/18. */@Controller@RequestMapping("/users")public class HomeController { @Autowired UserService userService; @RequestMapping(method = RequestMethod.GET) @ResponseBody public String getUsers() { return "getUsers"; } @Secured({"ROLE_ADMIN","ROLE_USER"})//此方法只允许 ROLE_ADMIN 和ROLE_USER 角色 访问 @RequestMapping(method = RequestMethod.POST) @ResponseBody public Object save(@RequestBody SysUser user) { return userService.create(user); } @Secured("ROLE_ADMIN")//此方法只允许 ROLE_ADMIN 角色访问 @RequestMapping(method = RequestMethod.PUT) @ResponseBody public String update() { return "updateUser"; } @Secured("ROLE_ADMIN")//此方法只允许 ROLE_ADMIN 角色访问 @RequestMapping(method = RequestMethod.DELETE) @ResponseBody public String delete() { return "deleteUser"; }}7. 测试
使用admin 登录
关于登录方式请移步: springSecurity 之 http Basic认证 (四)
可以访问 /users 路径下的get、post、put、delete 四个请求方法
使用abel 登录 可以访问 /users 路径下的get、post 两个请求方法 访问 put、delete 方法会抛403 没有权限异常
本文源码:https://github.com/527515025/springBoot