pom文件
org.springframework.boot
spring-boot-starter-security
org.springframework.security.oauth
spring-security-oauth2
2.3.3.RELEASE
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-logging
用户实体
为了方便操作,给用户赋权限(上篇使用了Security 的 USER对象,这次换个方式耍耍吧)
/**
* @Title: LoginAppUser
* @description: 用户信息管理
* @author: LIUFANG
* @create: 2020/3/13 12:54
* @Version: v1.0
*/
@Getter
@Setter
public class LoginAppUser implements UserDetails {
private Long id;
private String username;
private String password;
private String nickname;
private String headImgUrl;
private String phone;
private Integer sex;
/**
* 状态
*/
private Boolean enabled;
private String type;
private String deptId;
private String deptName;
private Date createTime;
private Date updateTime;
private Set sysRoles;
private Set permissions;
/**权限的操作直接放在此处了,简单粗暴,如果你开心,你可以把类做的细化一点*/
@Override
public Collection extends GrantedAuthority> getAuthorities() {
Collection collection = new HashSet<>();
/**为什么加ROLE_,看了一下源码,你可以理解为:区分资源和权限的标识符*/
collection.add(new SimpleGrantedAuthority("ROLE_"+"USER"));
return collection;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public String getUsername() {
/**写死的数据,真实开发查询数据库就OK了*/
return "user";
}
UserDetailsService
/**
* @Title: MyUserDetailsService
* @description: 用户管理
* @author: LIUFANG
* @create: 2020/3/13 9:27
* @Version: v1.0
*/
@Component
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private PasswordEncoder userPasswordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
LoginAppUser loginAppUser = new LoginAppUser();
loginAppUser.setUsername("user");
loginAppUser.setPassword(userPasswordEncoder.encode("123456"));
return loginAppUser;
}
}
WebSecurityConfig
/**
* @Title: SecurityConfig
* @description: 权限配置
* @author: LIUFANG
* @create: 2020/3/13 9:12
* @Version: v1.0
*/
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@Configuration
@Order(2)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailsService userDetailsService;
/**
* 一定要将 userDetailsService 设置到 AuthenticationManagerBuilder 中
* 不然后面校验ClientDetailsService时会找不到UsernamePasswordToken的Provider
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(userPasswordEncoder());
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.requestMatchers().antMatchers("/oauth/**","/login/**","/logout/**")
.and()
.authorizeRequests()
.antMatchers("/oauth/**").authenticated()
.and()
.formLogin().permitAll(); //新增login form支持用户登录及授权
}
@Bean
public PasswordEncoder userPasswordEncoder(){
return new BCryptPasswordEncoder();
}
/**
* 覆盖WebSecurityConfigurerAdapter类(本类集成的爸爸)authenticationManagerBean的方法,最终要的一点,重写的时候,直接使用super就OK,这波操作给6分
* 注意的是,这个bean不重写,在OauthAuthorizationServerConfig是无法获取的,这个是个小坑
* @return
* @throws Exception
*/
@Bean
@Override
protected AuthenticationManager authenticationManager() throws Exception{
return super.authenticationManager();
}
Oauth 配置类
/**
* @Title: OauthAuthorizationServerConfig
* @description: Oauth2.0配置
* @author: LIUFANG
* @create: 2020/3/13 10:22
* @Version: v1.0
*/
@Configuration
@EnableAuthorizationServer
public class OauthAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
/**这个地方需要注意一下,这个bean必须自行创建出来,参照WebSecurityConfig类*/
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private MyUserDetailsService userDetailsService;
/**
* 配置访问端点和令牌服务
* @param security
* @throws Exception
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
/**注意这个allowFormAuthenticationForClients,开启表单验证*/
security
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()")
.allowFormAuthenticationForClients();
}
/**
* 用来配置客户端详情服务
* @param clients
* @throws Exception
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
/**client信息,可以存储数据库,可以redis,也可以存储内存,看你心情*/
clients.inMemory()
.withClient("system")
.secret(passwordEncoder.encode("123456"))
.authorizedGrantTypes("authorization_code", "refresh_token", "password")
.scopes("app");
}
/**
* 配置token
* @param endpoints
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
/**直接存储内存*/
endpoints
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
.authenticationManager(authenticationManager)
.tokenStore(new InMemoryTokenStore())
.userDetailsService(userDetailsService);
}
}
ResourceServerConfig资源服务器
这个类的作用是为Oauth请求服务,必须配置
/**
* @Title: ResourceServerConfig
* @description: 资源服务配置
* @author: LIUFANG
* @create: 2020/3/13 13:54
* @Version: v1.0
*/
@Configuration
@EnableResourceServer
@Order(6)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasAnyRole("ADMIN","USER")
.antMatchers("/test").authenticated()
.anyRequest().authenticated();
}
}
controller调用
/**
* @Title: MyController
* @description: 测试Controller
* @author: LIUFANG
* @create: 2020/3/13 10:56
* @Version: v1.0
*/
@RestController
public class MyController {
@GetMapping(value = "/test")
public Object test(){
return "test";
}
@GetMapping(value = "/user")
@PreAuthorize("hasAnyRole('ROLE_USER')")
public Object user(){
return "user";
}
@GetMapping(value = "/user/a")
public Object user2(){
return "user";
}
@PreAuthorize("hasAnyRole('ROLE_ADMIN')")
@GetMapping(value = "/admin")
public Object admin(){
return "admin";
}
@GetMapping(value = "/admin/b")
public Object admin2(){
return "admin";
}
}
http请求验证
/**http 请求 URL*/
GET http://localhost:8888/user/a
/**header中需要添加消息头:*/
Authorization: Bearer 775d36ad-d224-463b-8632-9cc4e9518d41
获取code
http://localhost:8080/oauth/authorize?client_id=system&response_type=code&scope=app&redirect_uri=http://www.baidu.com
使用code 获取access_token
curl -X POST -d "grant_type=authorization_code&code=Ii2ZNI&client_id=system&client_secret=123456&redirect_uri=http://www.baidu.com" http://localhost:8080/oauth/token
出参:
{
"access_token": "df23f20a-59ee-4288-9582-040718846ff3",
"token_type": "bearer",
"refresh_token": "63b0ad83-6168-4b62-abeb-ab64d1154abd",
"expires_in": 43199,
"scope": "app"
}
参考:
https://blog.csdn.net/liu__hui2008ooo/article/details/104904137
https://blog.csdn.net/qq_27828675/article/details/82466599