前言:
根据oauth2协议,采用code授权模式,通过调用/oauth/authorize获取授权码,在通过授权码获取token,这样就可以通过token访问资源服务器接口了。
一. 编写认证服务器项目
springboot版本2.x,spring oauth2采用2.0,引入依赖
<!-- 由于一些注解和API从spring security5.0中移除,所以需要导入下面的依赖包 --> <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> <version>2.0.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency>
配置授权服务器: OAuth2AuthorizationServer
//授权服务器配置 @Configuration @EnableAuthorizationServer public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter { @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("clientapp") .secret("112233") .redirectUris("http://localhost:9001/callbackCode") // 授权码模式 .authorizedGrantTypes("authorization_code") .scopes("read_userinfo", "read_contacts"); } }
配置资源服务器:OAuth2ResourceServer
/** * 权限拦截在资源拦截前面 */ @Configuration @EnableResourceServer public class OAuth2ResourceServer extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest() .authenticated() .and() .requestMatchers() .antMatchers("/api/**"); } }
配置登陆认证:SecurityConfig
/** * @author LLJia * @version 1.0 * @date 2019/9/11 10:12 */ @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .passwordEncoder(new Md5PasswordEncoder()) .withUser("admin") .password(new Md5PasswordEncoder().encode("123456")) .roles("USER"); } @Bean public Md5PasswordEncoder passwordEncoder() { return new Md5PasswordEncoder(); } }
配置資源api
@Controller public class UserController { // 资源API @RequestMapping("/api/userinfo") public ResponseEntity<UserInfo> getUserInfo() { User user = (User) SecurityContextHolder.getContext() .getAuthentication().getPrincipal(); String email = user.getUsername() + "@spring2go.com"; UserInfo userInfo = new UserInfo(); userInfo.setName(user.getUsername()); userInfo.setEmail(email); return ResponseEntity.ok(userInfo); } }
二. 配置客戶端
2.1 code模式
简单的spring web服务器,配置获取授权码和token链接
oauth.authorize=http://localhost:8080/oauth/authorizeclient_id=clientapp&redirect_uri=http://localhost:9001/callbackCode&response_type=code&scope=read_userinfo oauth.token=http://localhost:8080/oauth/token?grant_type=authorization_code&redirect_uri=http://localhost:9001/callbackCode&scope=read_userinfo
配置访问用户信息接口
@RequestMapping("/userInfo") public String useInfo(HttpServletRequest request, Model model) { HttpSession session = request.getSession(); Object token = session.getAttribute("access_token"); //token空跳转到认证服务器认证 if (token == null) { return "redirect:" + oauthAuthorizeUrl; } //通过token获取用户信息 String userUrl = "http://localhost:8080/api/userinfo?access_token=" + token; String result3 = HttpRequest.post(userUrl) .timeout(20000)//超时,毫秒 .execute().body(); model.addAttribute("userInfo", result3); return "userInfo"; }
配置获取code回调接口
@RequestMapping("/callbackCode") public String callbackCode(HttpServletRequest request) { //获取授权码 String code = request.getParameter("code"); // 通过授权码调用token接口获取token String url = oauthTokenUrl + "&code=" + code; if (code != null && !code.equals("")) { String result2 = HttpRequest.post(url) .basicAuth("clientapp", "112233") .timeout(20000)//超时,毫秒 .execute().body(); JSONObject jsonObject = JSONUtil.parseObj(result2); String access_token = jsonObject.getStr("access_token"); HttpSession session = request.getSession(); //存储session里 session.setAttribute("access_token", access_token); return "redirect:userInfo"; } else { return "CodeError"; } }
三. 测试
访问客户端用户接口 http://localhost:9001/userInfo,判断token不在跳转到认证服务器认证
登陆成功调用客户端回调接口处理:
通过认证服务器返回的code调用认证服务器/oauth/token获取token,token存储到session跳转到用户action,用户action通过token访问资源服务器用户信息