オンラインの研究 - 16日目 - 講義 - 春のセキュリティのOAuth2 JWT 7

4.3  認証サービス 
4.3.1  要件分析
:および認証サービスは、次のような機能を実装する必要が 
1 インタフェースログイン、 
フロントエンドのポストトークンを生成することにより、アカウント、パスワードおよび他のユーザID認証の申請をし、トークンが中に保存されているのRedis 。 
トークン書き込みクッキー。 
2 インタフェースを終了し 
、現在のユーザーの身元のは正当であると検証され、ログに記録されています。 
以下からのトークンのRedisは削除しました。 
削除クッキーのトークンを。 
次のようにビジネスプロセスは以下のとおりです。
 

4.3.2アピインタフェース

@Api(value = "用户认证",description = "用户认证接口")
public interface AuthControllerApi {
@ApiOperation("登录")
public LoginResult login(LoginRequest loginRequest);
@ApiOperation("退出")
public ResponseResult logout();
}

4.3.3  設定パラメータ 
application.yml 設定パラメータ

auth:
tokenValiditySeconds: 1200 #token存储到redis的过期时间
clientId: XcWebApp
clientSecret: XcWebApp
cookieDomain: localhost
cookieMaxAge: ‐1

4.3.4  アプリケーショントークンのテスト 
を破壊しないために、春のセキュリティコードを、我々サービスの方法によってRestTemplate 要求春のセキュリティは、アプリケーションが行うさらさ以下、トークンインターフェースカードアプリケーションは、テストコードです:

@SpringBootTest
@RunWith(SpringRunner.class)
public class TestClient {
@Autowired
LoadBalancerClient loadBalancerClient;
@Autowired
RestTemplate restTemplate;
@Test
public void testClient(){
//采用客户端负载均衡,从eureka获取认证服务的ip 和端口
ServiceInstance serviceInstance =
loadBalancerClient.choose(XcServiceList.XC_SERVICE_UCENTER_AUTH);
URI uri = serviceInstance.getUri();
String authUrl = uri+"/auth/oauth/token";
//URI url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType
// url就是 申请令牌的url /oauth/token
//method http的方法类型
//requestEntity请求内容
//responseType,将响应的结果生成的类型
//请求的内容分两部分
//1、header信息,包括了http basic认证信息
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
String httpbasic = httpbasic("XcWebApp", "XcWebApp");
//"Basic WGNXZWJBcHA6WGNXZWJBcHA="
headers.add("Authorization", httpbasic);
//2、包括:grant_type、username、passowrd
MultiValueMap<String, String> body = new LinkedMultiValueMap<String, String>();
body.add("grant_type","password");
body.add("username","itcast");
body.add("password","123");
HttpEntity<MultiValueMap<String, String>> multiValueMapHttpEntity = new
HttpEntity<MultiValueMap<String, String>>(body, headers);
//指定 restTemplate当遇到400或401响应时候也不要抛出异常,也要正常返回值
restTemplate.setErrorHandler(new DefaultResponseErrorHandler(){
@Override
public void handleError(ClientHttpResponse response) throws IOException {
//当响应的值为400或401时候也要正常响应,不要抛出异常
if(response.getRawStatusCode()!=400 && response.getRawStatusCode()!=401){
super.handleError(response);
}
}
});
//远程调用申请令牌
ResponseEntity<Map> exchange = restTemplate.exchange(authUrl, HttpMethod.POST,
multiValueMapHttpEntity, Map.class);
Map body1 = exchange.getBody();
System.out.println(body1);
}
private String httpbasic(String clientId,String clientSecret){
//将客户端id和客户端密码拼接,按“客户端id:客户端密码”
String string = clientId+":"+clientSecret;
//进行base64编码
byte[] encode = Base64.encode(string.getBytes());
return "Basic "+new String(encode);
}
}

4.3.4ダオ 
一時的に使用する静的データは、ユーザーのログインユーザ情報データベースの検証再接続を介して転送されます。
4.3.5サービスは、
保存されたトークンとトークン認証サービス要求を呼び出します  Redisのを。 
1 持つAuthTokenは、 
作成  持つAuthTokenのモデルクラス、IDトークン、リフレッシュトークン、トークンを含むストレージ・アプリケーション、JWT トークン 
のユーザ認証するかどうかのチェック:トークンIDを 
:リフレッシュトークンJWT トークンがいつ期限切れにするように、Aリフレッシュブランドは、 
JWT トークン:認可のために

@Data
@ToString
@NoArgsConstructor
public class AuthToken {
String access_token;//身份token
String refresh_token;//刷新token
String jwt_token;//jwt令牌
}

アプリケーショントークンサービス次のように:

@Service
public class AuthService {
private static final Logger LOGGER = LoggerFactory.getLogger(AuthService.class);
@Value("${auth.tokenValiditySeconds}")
int tokenValiditySeconds;
@Autowired
RestTemplate restTemplate;
@Autowired
LoadBalancerClient loadBalancerClient;
@Autowired
StringRedisTemplate stringRedisTemplate;
//认证方法
public AuthToken login(String username,String password,String clientId,String clientSecret){
//申请令牌
AuthToken authToken = applyToken(username,password,clientId, clientSecret);
if(authToken == null){
ExceptionCast.cast(AuthCode.AUTH_LOGIN_APPLYTOKEN_FAIL);
}
//将 token存储到redis
String access_token = authToken.getAccess_token();
String content = JSON.toJSONString(authToken);
boolean saveTokenResult = saveToken(access_token, content, tokenValiditySeconds);
if(!saveTokenResult){
ExceptionCast.cast(AuthCode.AUTH_LOGIN_TOKEN_SAVEFAIL);
}
return authToken;
}
//存储令牌到redis
private boolean saveToken(String access_token,String content,long ttl){
//令牌名称
String name = "user_token:" + access_token;
//保存到令牌到redis
stringRedisTemplate.boundValueOps(name).set(content,ttl, TimeUnit.SECONDS);
//获取过期时间
Long expire = stringRedisTemplate.getExpire(name);
return expire>0;
}
//认证方法
private AuthToken applyToken(String username,String password,String clientId,String
clientSecret){
//选中认证服务的地址
ServiceInstance serviceInstance =
loadBalancerClient.choose(XcServiceList.XC_SERVICE_UCENTER_AUTH);
if (serviceInstance == null) {
LOGGER.error("choose an auth instance fail");
ExceptionCast.cast(AuthCode.AUTH_LOGIN_AUTHSERVER_NOTFOUND);
}
//获取令牌的url
String path = serviceInstance.getUri().toString()+"/auth/oauth/token";
//定义body
MultiValueMap<String,String> formData = new LinkedMultiValueMap<>();
//授权方式
formData.add("grant_type", "password");
//账号
formData.add("username",username);
//密码
formData.add("password", password);
//定义头
MultiValueMap<String,String> header = new LinkedMultiValueMap<>();
header.add("Authorization", httpbasic(clientId,clientSecret));
//指定 restTemplate当遇到400或401响应时候也不要抛出异常,也要正常返回值
restTemplate.setErrorHandler(new DefaultResponseErrorHandler(){
@Override
public void handleError(ClientHttpResponse response) throws IOException {
//当响应的值为400或401时候也要正常响应,不要抛出异常
if(response.getRawStatusCode()!=400 && response.getRawStatusCode()!=401){
super.handleError(response);
}
}
});
Map map = null;
try {
//http请求spring security的申请令牌接口
ResponseEntity<Map> mapResponseEntity = restTemplate.exchange(path, HttpMethod.POST,
new HttpEntity<MultiValueMap<String, String>>(formData, header), Map.class);
map = mapResponseEntity.getBody();
} catch (RestClientException e) {
e.printStackTrace();
LOGGER.error("request oauth_token_password error: {}",e.getMessage());
e.printStackTrace();
ExceptionCast.cast(AuthCode.AUTH_LOGIN_APPLYTOKEN_FAIL);
}
if(map == null ||
map.get("access_token") == null ||
map.get("refresh_token") == null ||
map.get("jti") == null){//jti是jwt令牌的唯一标识作为用户身份令牌
ExceptionCast.cast(AuthCode.AUTH_LOGIN_APPLYTOKEN_FAIL);
}
AuthToken authToken = new AuthToken();
//访问令牌(jwt)
String jwt_token = (String) map.get("access_token");
//刷新令牌(jwt)
String refresh_token = (String) map.get("refresh_token");
//jti,作为用户的身份标识
String access_token = (String) map.get("jti");
authToken.setJwt_token(jwt_token);
authToken.setAccess_token(access_token);
authToken.setRefresh_token(refresh_token);
return authToken;
}
//获取httpbasic认证串
private String httpbasic(String clientId,String clientSecret){
//将客户端id和客户端密码拼接,按“客户端id:客户端密码”
String string = clientId+":"+clientSecret;
//进行base64编码
byte[] encode = Base64.encode(string.getBytes());
return "Basic "+new String(encode);
}
}

コントローラー4.3.6 
AuthControllerのコードは以下の通りであります:

@RestController
public class AuthController implements AuthControllerApi {
@Value("${auth.clientId}")
String clientId;
@Value("${auth.clientSecret}")
String clientSecret;
@Value("${auth.cookieDomain}")
String cookieDomain;
@Value("${auth.cookieMaxAge}")
int cookieMaxAge;
@Value("${auth.tokenValiditySeconds}")
int tokenValiditySeconds;
@Autowired
AuthService authService;
@Override
@PostMapping("/userlogin")
public LoginResult login(LoginRequest loginRequest) {
//校验账号是否输入
if(loginRequest == null || StringUtils.isEmpty(loginRequest.getUsername())){
ExceptionCast.cast(AuthCode.AUTH_USERNAME_NONE);
}
//校验密码是否输入
if(StringUtils.isEmpty(loginRequest.getPassword())){
ExceptionCast.cast(AuthCode.AUTH_PASSWORD_NONE);
}
AuthToken authToken = authService.login(loginRequest.getUsername(),
loginRequest.getPassword(), clientId, clientSecret);
//将令牌写入cookie
//访问token
String access_token = authToken.getAccess_token();
//将访问令牌存储到cookie
saveCookie(access_token);
return new LoginResult(CommonCode.SUCCESS,access_token);
}
//将令牌保存到cookie
private void saveCookie(String token){
HttpServletResponse response = ((ServletRequestAttributes)
RequestContextHolder.getRequestAttributes()).getResponse();
//添加cookie 认证令牌,最后一个参数设置为false,表示允许浏览器获取
CookieUtil.addCookie(response, cookieDomain, "/", "uid", token, cookieMaxAge, false);
}
@Override
@PostMapping("/userlogout")
public ResponseResult logout() {
return null;
}
}

4.3.7  ログのURL リリース 
認証サービスは、ここであなたがログインする必要があり、デフォルトのユーザーID情報を確認する必要があり、URL のリリースを。
WebSecurityConfifig クラスのオーバーライド  confifigure(WebSecurity社ウェブ)メソッドを次のように

@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/userlogin");
}

4.3.8  テスト認証インタフェース 
使用して郵便配達のテストを: 
ポストの要求を:HTTP:// localhostを:40400 / AUTH / userloginの
 

4.3.9  テストライトクッキー 
クッキーは、最終的に書き込まれますxuecheng.com により、ドメイン名の下でnginxの認証プロキシのテストクッキーの書き込みが成功したかどうか。 
1 、構成nginxののプロキシ 

在ucenter.xuecheng.com下配置代理路径
 #认证
location ^~ /openapi/auth/ {
proxy_pass http://auth_server_pool/auth/;
}

追加:

#认证服务
upstream auth_server_pool{
server 127.0.0.1:40400 weight=10;
}

2 、要求:http://ucenter.xuecheng.com/openapi/auth/userlogin 
観測クッキーの書き込み結果

835元記事公開 ウォンの賞賛152 ビューに14万+を

おすすめ

転載: blog.csdn.net/qq_40208605/article/details/104393524